improved support for enums
[cparser] / parser.c
index 66d44c2..278c524 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -14,6 +14,7 @@
 #include "adt/array.h"
 
 //#define PRINT_TOKENS
+//#define ABORT_ON_ERROR
 #define MAX_LOOKAHEAD 2
 
 struct environment_entry_t {
@@ -87,7 +88,7 @@ static inline
 const token_t *la(int num)
 {
        assert(num > 0 && num <= MAX_LOOKAHEAD);
-       int pos = (num-1) % MAX_LOOKAHEAD;
+       int pos = (lookahead_bufpos+num-1) % MAX_LOOKAHEAD;
        return & lookahead_buffer[pos];
 }
 
@@ -104,6 +105,9 @@ void parser_print_error_prefix_pos(const source_position_t source_position)
     fputc(':', stderr);
     fprintf(stderr, "%d", source_position.linenr);
     fputs(": error: ", stderr);
+#ifdef ABORT_ON_ERROR
+       abort();
+#endif
 }
 
 void parser_print_error_prefix(void)
@@ -351,35 +355,48 @@ static type_t *parse_union_specifier(void)
        return (type_t*) union_type;
 }
 
-static void parse_enum_type_entries(void)
+static enum_entry_t *parse_enum_type_entries(void)
 {
        eat('{');
 
        if(token.type == '}') {
                next_token();
                parse_error("empty enum not allowed");
-               return;
+               return NULL;
        }
 
+       enum_entry_t *result     = NULL;
+       enum_entry_t *last_entry = NULL;
        do {
+               enum_entry_t *entry = allocate_ast_zero(sizeof(entry[0]));
                if(token.type != T_IDENTIFIER) {
                        parse_error_expected("problem while parsing enum entry",
                                             T_IDENTIFIER, 0);
                        eat_until('}');
-                       return;
+                       return result;
                }
+               entry->symbol = token.v.symbol;
                next_token();
 
                if(token.type == '=') {
-                       parse_constant_expression();
+                       next_token();
+                       entry->value = parse_constant_expression();
                }
 
+               if(last_entry != NULL) {
+                       last_entry->next = entry;
+               } else {
+                       result = entry;
+               }
+               last_entry = entry;
+
                if(token.type != ',')
                        break;
                next_token();
        } while(token.type != '}');
 
-       expect_void('}');
+       expect('}');
+       return result;
 }
 
 static type_t *parse_enum_specifier(void)
@@ -394,10 +411,10 @@ static type_t *parse_enum_specifier(void)
                enum_type->symbol = token.v.symbol;
                next_token();
                if(token.type == '{') {
-                       parse_enum_type_entries();
+                       enum_type->entries = parse_enum_type_entries();
                }
        } else if(token.type == '{') {
-               parse_enum_type_entries();
+               enum_type->entries = parse_enum_type_entries();
        } else {
                parse_error_expected("problem while parsing enum type specifiers",
                                     T_IDENTIFIER, '{');
@@ -406,6 +423,72 @@ static type_t *parse_enum_specifier(void)
        return (type_t*) enum_type;
 }
 
+static
+const char *parse_string_literals(void)
+{
+       assert(token.type == T_STRING_LITERAL);
+       const char *result = token.v.string;
+
+       next_token();
+
+       while(token.type == T_STRING_LITERAL) {
+               result = concat_strings(result, token.v.string);
+               next_token();
+       }
+
+       return result;
+}
+
+static
+void parse_attributes(void)
+{
+       while(1) {
+               switch(token.type) {
+               case T___attribute__:
+                       next_token();
+
+                       expect_void('(');
+                       int depth = 1;
+                       while(depth > 0) {
+                               switch(token.type) {
+                               case T_EOF:
+                                       parse_error("EOF while parsing attribute");
+                                       break;
+                               case '(':
+                                       next_token();
+                                       depth++;
+                                       break;
+                               case ')':
+                                       next_token();
+                                       depth--;
+                                       break;
+                               default:
+                                       next_token();
+                               }
+                       }
+                       break;
+               case T_asm:
+                       next_token();
+                       expect_void('(');
+                       if(token.type != T_STRING_LITERAL) {
+                               parse_error_expected("while parsing assembler attribute",
+                                                    T_STRING_LITERAL);
+                               eat_until(')');
+                               break;
+                       } else {
+                               parse_string_literals();
+                       }
+                       expect_void(')');
+                       break;
+               default:
+                       goto attributes_finished;
+               }
+       }
+
+attributes_finished:
+       ;
+}
+
 typedef enum {
        SPECIFIER_SIGNED    = 1 << 0,
        SPECIFIER_UNSIGNED  = 1 << 1,
@@ -589,6 +672,11 @@ void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        next_token();
                        break;
 
+               case T___attribute__:
+                       /* TODO */
+                       parse_attributes();
+                       break;
+
                case T_IDENTIFIER:
                        declaration = token.v.symbol->declaration;
                        if(declaration == NULL ||
@@ -860,7 +948,7 @@ void parse_parameters(method_type_t *type)
                return;
        }
 
-       declaration_t *declaration;
+       declaration_t           *declaration;
        method_parameter_type_t *parameter_type;
        method_parameter_type_t *last_parameter_type = NULL;
 
@@ -896,34 +984,6 @@ void parse_parameters(method_type_t *type)
        }
 }
 
-static
-void parse_attributes(void)
-{
-       while(token.type == T___attribute__) {
-               next_token();
-
-               expect_void('(');
-               int depth = 1;
-               while(depth > 0) {
-                       switch(token.type) {
-                       case T_EOF:
-                               parse_error("EOF while parsing attribute");
-                               break;
-                       case '(':
-                               next_token();
-                               depth++;
-                               break;
-                       case ')':
-                               next_token();
-                               depth--;
-                               break;
-                       default:
-                               next_token();
-                       }
-               }
-       }
-}
-
 typedef struct declarator_part declarator_part;
 struct declarator_part {
        parsed_pointer_t *pointers;
@@ -941,6 +1001,9 @@ declarator_part *parse_inner_declarator(declaration_t *declaration,
 
        part->pointers = parse_pointers();
 
+       /* TODO: find out if this is correct */
+       parse_attributes();
+
        switch(token.type) {
        case T_IDENTIFIER:
                if(declaration == NULL) {
@@ -1226,9 +1289,7 @@ expression_t *parse_string_const(void)
        string_literal_t *cnst = allocate_ast_zero(sizeof(cnst[0]));
 
        cnst->expression.type = EXPR_STRING_LITERAL;
-       cnst->value           = token.v.string;
-
-       next_token();
+       cnst->value           = parse_string_literals();
 
        return (expression_t*) cnst;
 }
@@ -1259,11 +1320,44 @@ expression_t *parse_reference(void)
        return (expression_t*) ref;
 }
 
+static
+expression_t *parse_cast(void)
+{
+       unary_expression_t *cast = allocate_ast_zero(sizeof(cast[0]));
+
+       cast->expression.type            = EXPR_UNARY;
+       cast->type                       = UNEXPR_CAST;
+       cast->expression.source_position = token.source_position;
+
+       type_t *type  = parse_typename();
+
+       expect(')');
+       expression_t *value = parse_sub_expression(20);
+
+       cast->expression.datatype = type;
+       cast->value               = value;
+
+       return (expression_t*) cast;
+}
+
 static
 expression_t *parse_brace_expression(void)
 {
        eat('(');
 
+       declaration_t *declaration;
+       switch(token.type) {
+       TYPE_QUALIFIERS
+       TYPE_SPECIFIERS
+               return parse_cast();
+       case T_IDENTIFIER:
+               declaration = token.v.symbol->declaration;
+               if(declaration != NULL &&
+                               (declaration->storage_class & STORAGE_CLASS_TYPEDEF)) {
+                       return parse_cast();
+               }
+       }
+
        expression_t *result = parse_expression();
        expect(')');
 
@@ -1898,7 +1992,7 @@ statement_t *parse_compound_statement(void)
 
        statement_t *last_statement = NULL;
 
-       while(token.type != '}') {
+       while(token.type != '}' && token.type != T_EOF) {
                statement_t *statement = parse_statement();
 
                if(last_statement != NULL) {