static declaration_t *last_declaration = NULL;
static struct obstack temp_obst;
+static type_t *type_int = NULL;
+static type_t *type_const_char = NULL;
+static type_t *type_string = NULL;
+static type_t *type_void = NULL;
+static type_t *type_size_t = NULL;
+
static statement_t *parse_compound_statement(void);
static statement_t *parse_statement(void);
* called when we find a 2nd declarator for an identifier we already have a
* declarator for
*/
-static int is_compatible_declaration (declaration_t *declaration,
+static bool is_compatible_declaration (declaration_t *declaration,
declaration_t *previous)
{
/* TODO: not correct yet */
static inline declaration_t *environment_push(declaration_t *declaration,
const void *context)
{
- environment_entry_t *entry
- = obstack_alloc(&environment_obstack, sizeof(entry[0]));
- memset(entry, 0, sizeof(entry[0]));
-
- int top = ARR_LEN(environment_stack);
- ARR_RESIZE(environment_stack, top + 1);
- environment_stack[top] = entry;
-
- assert(declaration->source_position.input_name != NULL);
-
symbol_t *symbol = declaration->symbol;
assert(declaration != symbol->declaration);
+ assert(declaration->source_position.input_name != NULL);
if(symbol->context == context) {
declaration_t *previous_declaration = symbol->declaration;
}
}
+ environment_entry_t *entry
+ = obstack_alloc(&environment_obstack, sizeof(entry[0]));
+ memset(entry, 0, sizeof(entry[0]));
+
+ int top = ARR_LEN(environment_stack);
+ ARR_RESIZE(environment_stack, top + 1);
+ environment_stack[top] = entry;
+
entry->old_declaration = symbol->declaration;
entry->old_context = symbol->context;
entry->symbol = symbol;
return NULL;
}
-static type_t *parse_compound_type_specifier(int is_struct)
+static type_t *parse_compound_type_specifier(bool is_struct)
{
if(is_struct) {
eat(T_struct);
/* TODO: if type != NULL for the following rules issue an error */
case T_struct:
- type = parse_compound_type_specifier(1);
+ type = parse_compound_type_specifier(true);
break;
case T_union:
- type = parse_compound_type_specifier(0);
+ type = parse_compound_type_specifier(false);
break;
case T_enum:
type = parse_enum_specifier();
specifiers->type = result;
}
-static unsigned parse_type_qualifiers(void)
+static type_qualifier_t parse_type_qualifiers(void)
{
- unsigned type_qualifiers = 0;
+ type_qualifier_t type_qualifiers = 0;
while(true) {
switch(token.type) {
}
}
-typedef struct parsed_pointer_t parsed_pointer_t;
-struct parsed_pointer_t {
- unsigned type_qualifiers;
- parsed_pointer_t *next;
-};
-
-static parsed_pointer_t *parse_pointers(void)
-{
- parsed_pointer_t *result = NULL;
- parsed_pointer_t *last_pointer = NULL;
-
- while(token.type == '*') {
- next_token();
- parsed_pointer_t *pointer
- = obstack_alloc(&temp_obst, sizeof(pointer[0]));
- pointer->type_qualifiers = parse_type_qualifiers();
-
- if(last_pointer != NULL) {
- last_pointer->next = pointer;
- } else {
- result = pointer;
- }
- last_pointer = pointer;
- }
-
- return result;
-}
-
-static type_t *make_pointers(type_t *type, parsed_pointer_t *pointer)
-{
- for( ; pointer != NULL; pointer = pointer->next) {
- pointer_type_t *pointer_type
- = allocate_type_zero(sizeof(pointer_type[0]));
- pointer_type->type.type = TYPE_POINTER;
- pointer_type->points_to = type;
- pointer_type->type.qualifiers = pointer->type_qualifiers;
-
- type_t *result = typehash_insert((type_t*) pointer_type);
- if(result != (type_t*) pointer_type) {
- obstack_free(type_obst, pointer_type);
- }
-
- type = result;
- }
-
- return type;
-}
-
static void parse_identifier_list(void)
{
while(true) {
}
}
-typedef struct declarator_part declarator_part;
-struct declarator_part {
- parsed_pointer_t *pointers;
+typedef enum {
+ CONSTRUCT_POINTER,
+ CONSTRUCT_METHOD,
+ CONSTRUCT_ARRAY
+} construct_type_type_t;
+
+typedef struct construct_type_t construct_type_t;
+struct construct_type_t {
+ construct_type_type_t type;
+ construct_type_t *next;
+};
+
+typedef struct parsed_pointer_t parsed_pointer_t;
+struct parsed_pointer_t {
+ construct_type_t construct_type;
+ type_qualifier_t type_qualifiers;
+};
+
+typedef struct construct_method_type_t construct_method_type_t;
+struct construct_method_type_t {
+ construct_type_t construct_type;
method_type_t *method_type;
- declarator_part *inner;
};
+typedef struct parsed_array_t parsed_array_t;
+struct parsed_array_t {
+ construct_type_t construct_type;
+ type_qualifier_t type_qualifiers;
+ bool is_static;
+ bool is_variable;
+ expression_t *size;
+};
+
+typedef struct construct_base_type_t construct_base_type_t;
+struct construct_base_type_t {
+ construct_type_t construct_type;
+ type_t *type;
+};
+
+static construct_type_t *parse_pointer_declarator(void)
+{
+ eat('*');
+
+ parsed_pointer_t *pointer = obstack_alloc(&temp_obst, sizeof(pointer[0]));
+ memset(pointer, 0, sizeof(pointer[0]));
+ pointer->type_qualifiers = parse_type_qualifiers();
+
+ return (construct_type_t*) pointer;
+}
+
+static construct_type_t *parse_array_declarator(void)
+{
+ eat('[');
+
+ parsed_array_t *array = obstack_alloc(&temp_obst, sizeof(array[0]));
+ memset(array, 0, sizeof(array[0]));
+
+ if(token.type == T_static) {
+ array->is_static = true;
+ next_token();
+ }
+
+ type_qualifier_t type_qualifiers = parse_type_qualifiers();
+ if(type_qualifiers != 0) {
+ if(token.type == T_static) {
+ array->is_static = true;
+ next_token();
+ }
+ }
+ array->type_qualifiers = type_qualifiers;
+
+ if(token.type == '*' && look_ahead(1)->type == ']') {
+ array->is_variable = true;
+ next_token();
+ } else if(token.type != ']') {
+ array->size = parse_assignment_expression();
+ }
+
+ expect(']');
+
+ return (construct_type_t*) array;
+}
-static declarator_part *parse_inner_declarator(declaration_t *declaration,
- int may_be_abstract)
+static construct_type_t *parse_method_declarator(declaration_t *declaration)
{
- declarator_part *part = obstack_alloc(&temp_obst, sizeof(part[0]));
- memset(part, 0, sizeof(part[0]));
+ eat('(');
+
+ method_type_t *method_type
+ = allocate_type_zero(sizeof(method_type[0]));
+ method_type->type.type = TYPE_METHOD;
- part->pointers = parse_pointers();
+ declaration_t *parameters = parse_parameters(method_type);
+ if(declaration != NULL) {
+ declaration->context.declarations = parameters;
+ }
+
+ construct_method_type_t *construct_method_type =
+ obstack_alloc(&temp_obst, sizeof(construct_method_type[0]));
+ memset(construct_method_type, 0, sizeof(construct_method_type[0]));
+ construct_method_type->construct_type.type = CONSTRUCT_METHOD;
+ construct_method_type->method_type = method_type;
+
+ expect(')');
+
+ return (construct_type_t*) construct_method_type;
+}
+
+static construct_type_t *parse_inner_declarator(declaration_t *declaration,
+ int may_be_abstract)
+{
+ construct_type_t *result = NULL;
+ construct_type_t *last = NULL;
+
+ while(token.type == '*') {
+ construct_type_t *type = parse_pointer_declarator();
+ if(last != NULL) {
+ last->next = type;
+ } else {
+ result = type;
+ }
+ last = type;
+ }
/* TODO: find out if this is correct */
parse_attributes();
+ construct_type_t *inner_types = NULL;
+
switch(token.type) {
case T_IDENTIFIER:
if(declaration == NULL) {
break;
case '(':
next_token();
- part->inner = parse_inner_declarator(declaration, may_be_abstract);
+ inner_types = parse_inner_declarator(declaration, may_be_abstract);
expect(')');
break;
default:
}
while(true) {
+ construct_type_t *type;
switch(token.type) {
case '(':
- next_token();
-
- method_type_t *method_type
- = allocate_type_zero(sizeof(method_type[0]));
- method_type->type.type = TYPE_METHOD;
-
- declaration_t *parameters = parse_parameters(method_type);
- if(declaration != NULL) {
- declaration->context.declarations = parameters;
- }
-
- part->method_type = method_type;
-
- expect(')');
+ type = parse_method_declarator(declaration);
break;
case '[':
- next_token();
-
- if(token.type == T_static) {
- next_token();
- }
-
- unsigned type_qualifiers = parse_type_qualifiers();
- if(type_qualifiers != 0) {
- if(token.type == T_static) {
- next_token();
- }
- }
-
- /* TODO */
-
- if(token.type == '*' && look_ahead(1)->type == ']') {
- next_token();
- } else if(token.type != ']') {
- parse_assignment_expression();
- }
-
- expect(']');
+ type = parse_array_declarator();
break;
default:
goto declarator_finished;
}
+
+ if(last != NULL) {
+ last->next = type;
+ } else {
+ result = type;
+ }
+ last = type;
}
declarator_finished:
parse_attributes();
- return part;
+ if(inner_types != NULL) {
+ if(last != NULL) {
+ last->next = inner_types;
+ } else {
+ result = inner_types;
+ }
+ last = inner_types;
+ }
+
+ return result;
+}
+
+#if 0
+static type_t *make_pointers(type_t *type, parsed_pointer_t *pointer)
+{
+ for( ; pointer != NULL; pointer = pointer->next) {
+ pointer_type_t *pointer_type
+ = allocate_type_zero(sizeof(pointer_type[0]));
+ pointer_type->type.type = TYPE_POINTER;
+ pointer_type->points_to = type;
+ pointer_type->type.qualifiers = pointer->type_qualifiers;
+
+ type_t *result = typehash_insert((type_t*) pointer_type);
+ if(result != (type_t*) pointer_type) {
+ obstack_free(type_obst, pointer_type);
+ }
+
+ type = result;
+ }
+
+ return type;
}
+#endif
-static type_t *construct_declarator_type(declarator_part *part, type_t *type)
+static type_t *construct_declarator_type(construct_type_t *construct_list,
+ type_t *type)
{
- do {
- type = make_pointers(type, part->pointers);
+ construct_type_t *iter = construct_list;
+ for( ; iter != NULL; iter = iter->next) {
+ parsed_pointer_t *parsed_pointer;
+ parsed_array_t *parsed_array;
+ construct_method_type_t *construct_method_type;
+ method_type_t *method_type;
+ pointer_type_t *pointer_type;
+ array_type_t *array_type;
+
+ switch(iter->type) {
+ case CONSTRUCT_METHOD:
+ construct_method_type = (construct_method_type_t*) iter;
+ method_type = construct_method_type->method_type;
- method_type_t *method_type = part->method_type;
- if(method_type != NULL) {
method_type->result_type = type;
+ type = (type_t*) method_type;
+ break;
- type_t *result = typehash_insert((type_t*) method_type);
- if(result != (type_t*) method_type) {
- obstack_free(type_obst, method_type);
- }
- type = result;
+ case CONSTRUCT_POINTER:
+ parsed_pointer = (parsed_pointer_t*) iter;
+ pointer_type = allocate_type_zero(sizeof(pointer_type[0]));
+
+ pointer_type->type.type = TYPE_POINTER;
+ pointer_type->points_to = type;
+ pointer_type->type.qualifiers = parsed_pointer->type_qualifiers;
+ type = (type_t*) pointer_type;
+ break;
+
+ case CONSTRUCT_ARRAY:
+ parsed_array = (parsed_array_t*) iter;
+ array_type = allocate_type_zero(sizeof(array_type[0]));
+
+ array_type->type.type = TYPE_ARRAY;
+ array_type->element_type = type;
+ array_type->type.qualifiers = parsed_array->type_qualifiers;
+ array_type->is_static = parsed_array->is_static;
+ array_type->is_variable = parsed_array->is_variable;
+ array_type->size = parsed_array->size;
+ type = (type_t*) array_type;
+ break;
}
- part = part->inner;
- } while(part != NULL);
+ type_t *hashed_type = typehash_insert((type_t*) type);
+ if(hashed_type != type) {
+ obstack_free(type_obst, type);
+ type = hashed_type;
+ }
+ }
return type;
}
storage_class_t storage_class, type_t *type,
int may_be_abstract)
{
- declarator_part *part
+ construct_type_t *construct_type
= parse_inner_declarator(declaration, may_be_abstract);
- if(part != NULL) {
- declaration->type = construct_declarator_type(part, type);
- declaration->storage_class = storage_class;
- obstack_free(&temp_obst, part);
+ declaration->type = construct_declarator_type(construct_type, type);
+ declaration->storage_class = storage_class;
+ if(construct_type != NULL) {
+ obstack_free(&temp_obst, construct_type);
}
}
static type_t *parse_abstract_declarator(type_t *base_type)
{
- declarator_part *part = parse_inner_declarator(NULL, 1);
+ construct_type_t *construct_type
+ = parse_inner_declarator(NULL, 1);
- if(part == NULL)
+ if(construct_type == NULL)
return NULL;
- type_t *result = construct_declarator_type(part, base_type);
- obstack_free(&temp_obst, part);
+ type_t *result = construct_declarator_type(construct_type, base_type);
+ obstack_free(&temp_obst, construct_type);
return result;
}
{
string_literal_t *cnst = allocate_ast_zero(sizeof(cnst[0]));
- cnst->expression.type = EXPR_STRING_LITERAL;
- cnst->value = parse_string_literals();
+ cnst->expression.type = EXPR_STRING_LITERAL;
+ cnst->expression.datatype = type_string;
+ cnst->value = parse_string_literals();
return (expression_t*) cnst;
}
{
const_t *cnst = allocate_ast_zero(sizeof(cnst[0]));
- cnst->expression.type = EXPR_CONST;
- cnst->value = token.v.intvalue;
+ cnst->expression.type = EXPR_CONST;
+ cnst->expression.datatype = type_int;
+ cnst->value = token.v.intvalue;
next_token();
parser_print_error_prefix();
fprintf(stderr, "unknown symbol '%s' found.\n", ref->symbol->string);
}
- ref->declaration = ref->symbol->declaration;
+ ref->declaration = ref->symbol->declaration;
+ ref->expression.datatype = ref->declaration->type;
next_token();
return (expression_t*) ref;
}
+static void check_cast_allowed(expression_t *expression, type_t *dest_type)
+{
+ (void) expression;
+ (void) dest_type;
+ /* TODO check if cast is allowed and issue warnings/errors */
+}
+
static expression_t *parse_cast(void)
{
unary_expression_t *cast = allocate_ast_zero(sizeof(cast[0]));
expect(')');
expression_t *value = parse_sub_expression(20);
+ check_cast_allowed(value, type);
+
cast->expression.datatype = type;
cast->value = value;
expression->expression.type = EXPR_STATEMENT;
expression->statement = parse_compound_statement();
+ /* find last statement and use it's type */
+ const statement_t *last_statement = NULL;
+ const statement_t *statement = expression->statement;
+ for( ; statement != NULL; statement = statement->next) {
+ last_statement = statement;
+ }
+
+ if(last_statement->type == STATEMENT_EXPRESSION) {
+ const expression_statement_t *expression_statement =
+ (const expression_statement_t*) last_statement;
+ expression->expression.datatype
+ = expression_statement->expression->datatype;
+ } else {
+ expression->expression.datatype = type_void;
+ }
+
expect(')');
return (expression_t*) expression;
/* TODO */
string_literal_t *expression = allocate_ast_zero(sizeof(expression[0]));
- expression->expression.type = EXPR_FUNCTION;
- expression->value = "TODO: FUNCTION";
+ expression->expression.type = EXPR_FUNCTION;
+ expression->expression.datatype = type_string;
+ expression->value = "TODO: FUNCTION";
return (expression_t*) expression;
}
/* TODO */
string_literal_t *expression = allocate_ast_zero(sizeof(expression[0]));
- expression->expression.type = EXPR_PRETTY_FUNCTION;
- expression->value = "TODO: PRETTY FUNCTION";
+ expression->expression.type = EXPR_PRETTY_FUNCTION;
+ expression->expression.datatype = type_string;
+ expression->value = "TODO: PRETTY FUNCTION";
return (expression_t*) expression;
}
offsetof_expression_t *expression
= allocate_ast_zero(sizeof(expression[0]));
- expression->expression.type = EXPR_OFFSETOF;
+ expression->expression.type = EXPR_OFFSETOF;
+ expression->expression.datatype = type_size_t;
expect('(');
expression->type = parse_typename();
= allocate_ast_zero(sizeof(expression[0]));
expression->expression.type = EXPR_BUILTIN_SYMBOL;
+ /* TODO: set datatype */
+
expression->symbol = token.v.symbol;
next_token();
}
static expression_t *parse_array_expression(unsigned precedence,
- expression_t *array_ref)
+ expression_t *array_ref)
{
(void) precedence;
array_access_expression_t *array_access
= allocate_ast_zero(sizeof(array_access[0]));
- array_access->expression.type = EXPR_ARRAY_ACCESS;
- array_access->array_ref = array_ref;
- array_access->index = parse_expression();
+ array_access->expression.type = EXPR_ARRAY_ACCESS;
+ array_access->array_ref = array_ref;
+ array_access->index = parse_expression();
+
+ type_t *array_type = array_ref->datatype;
+ if(array_type != NULL) {
+ if(array_type->type == TYPE_POINTER) {
+ pointer_type_t *pointer = (pointer_type_t*) array_type;
+ array_access->expression.datatype = pointer->points_to;
+ } else {
+ parser_print_error_prefix();
+ fprintf(stderr, "array access on object with non-pointer type ");
+ print_type(array_type);
+ fprintf(stderr, "\n");
+ }
+ }
if(token.type != ']') {
parse_error_expected("Problem while parsing array access", ']', 0);
return (expression_t*) array_access;
}
-static type_t *get_expression_type(const expression_t *expression)
-{
- (void) expression;
- /* TODO */
- return NULL;
-}
-
-static int is_declaration_specifier(const token_t *token,
- int only_type_specifiers)
+static bool is_declaration_specifier(const token_t *token,
+ bool only_type_specifiers)
{
declaration_t *declaration;
sizeof_expression_t *sizeof_expression
= allocate_ast_zero(sizeof(sizeof_expression[0]));
- sizeof_expression->expression.type = EXPR_SIZEOF;
+ sizeof_expression->expression.type = EXPR_SIZEOF;
+ sizeof_expression->expression.datatype = type_size_t;
- if(token.type == '(' && is_declaration_specifier(look_ahead(1), 1)) {
+ if(token.type == '(' && is_declaration_specifier(look_ahead(1), true)) {
next_token();
sizeof_expression->type = parse_typename();
expect(')');
} else {
expression_t *expression = parse_sub_expression(precedence);
- sizeof_expression->type = get_expression_type(expression);
+ sizeof_expression->type = expression->datatype;
sizeof_expression->size_expression = expression;
}
select->expression.type = EXPR_SELECT;
select->compound = compound;
+ /* TODO: datatype */
+
if(token.type != T_IDENTIFIER) {
- parse_error_expected("Problem while parsing compound select",
- T_IDENTIFIER, 0);
+ parse_error_expected("Problem while parsing select", T_IDENTIFIER, 0);
return NULL;
}
select->symbol = token.v.symbol;
(void) precedence;
call_expression_t *call = allocate_ast_zero(sizeof(call[0]));
- call->expression.type = EXPR_CALL;
- call->method = expression;
+ call->expression.type = EXPR_CALL;
+ call->method = expression;
/* parse arguments */
eat('(');
}
expect(')');
+ type_t *type = expression->datatype;
+ if(type != NULL) {
+ /* we can call pointer to function */
+ if(type->type == TYPE_POINTER) {
+ pointer_type_t *pointer = (pointer_type_t*) type;
+ type = pointer->points_to;
+ }
+
+ if(type == NULL || type->type != TYPE_METHOD) {
+ parser_print_error_prefix();
+ fprintf(stderr, "expected a method type for call but found type ");
+ print_type(expression->datatype);
+ fprintf(stderr, "\n");
+ } else {
+ method_type_t *method_type = (method_type_t*) type;
+ call->expression.datatype = method_type->result_type;
+ }
+ }
+
return (expression_t*) call;
}
+static void type_error(const char *msg, const source_position_t source_position,
+ const type_t *type)
+{
+ parser_print_error_prefix_pos(source_position);
+ fprintf(stderr, "%s, but found type ", msg);
+ print_type(type);
+ fputc('\n', stderr);
+}
+
+static void type_error_incompatible(const char *msg,
+ const source_position_t source_position, const type_t *type1,
+ const type_t *type2)
+{
+ parser_print_error_prefix_pos(source_position);
+ fprintf(stderr, "%s, incompatible types: ", msg);
+ print_type(type1);
+ fprintf(stderr, " - ");
+ print_type(type2);
+ fprintf(stderr, ")\n");
+}
+
+static type_t *get_type_after_conversion(const type_t *type1,
+ const type_t *type2)
+{
+ /* TODO... */
+ (void) type2;
+ return (type_t*) type1;
+}
+
static expression_t *parse_conditional_expression(unsigned precedence,
expression_t *expression)
{
conditional_expression_t *conditional
= allocate_ast_zero(sizeof(conditional[0]));
+ conditional->expression.type = EXPR_CONDITIONAL;
conditional->condition = expression;
+ /* 6.5.15.2 */
+ type_t *condition_type = conditional->condition->datatype;
+ if(condition_type != NULL) {
+ if(!is_type_scalar(condition_type)) {
+ type_error("expected a scalar type", expression->source_position,
+ condition_type);
+ }
+ }
+
conditional->true_expression = parse_expression();
expect(':');
conditional->false_expression = parse_sub_expression(precedence);
+ type_t *true_type = conditional->true_expression->datatype;
+ if(true_type == NULL)
+ return (expression_t*) conditional;
+ type_t *false_type = conditional->false_expression->datatype;
+ if(false_type == NULL)
+ return (expression_t*) conditional;
+
+ /* 6.4.15.3 */
+ if(true_type == false_type) {
+ conditional->expression.datatype = true_type;
+ } else if(is_type_arithmetic(true_type) && is_type_arithmetic(false_type)) {
+ type_t *result = get_type_after_conversion(true_type, false_type);
+ /* TODO: create implicit convs if necessary */
+ conditional->expression.datatype = result;
+ } else if(true_type->type == TYPE_POINTER &&
+ false_type->type == TYPE_POINTER &&
+ true /* TODO compatible points_to types */) {
+ /* TODO */
+ } else if(/* (is_null_ptr_const(true_type) && false_type->type == TYPE_POINTER)
+ || (is_null_ptr_const(false_type) &&
+ true_type->type == TYPE_POINTER) TODO*/ false) {
+ /* TODO */
+ } else if(/* 1 is pointer to object type, other is void* */ false) {
+ /* TODO */
+ } else {
+ type_error_incompatible("problem while parsing conditional",
+ expression->source_position, true_type,
+ false_type);
+ }
+
return (expression_t*) conditional;
}
} else {
left = parse_primary_expression();
}
- if(left != NULL)
- left->source_position = source_position;
+ assert(left != NULL);
+ assert(left->type != EXPR_INVALID);
+ left->source_position = source_position;
while(true) {
if(token.type < 0) {
break;
left = parser->infix_parser(parser->infix_precedence, left);
- if(left != NULL)
- left->source_position = source_position;
+
+ assert(left != NULL);
+ assert(left->type != EXPR_INVALID);
+ left->source_position = source_position;
}
return left;
set_context(&statement->context);
if(token.type != ';') {
- if(is_declaration_specifier(&token, 0)) {
+ if(is_declaration_specifier(&token, false)) {
parse_declaration();
} else {
statement->initialisation = parse_expression();
{
init_expression_parsers();
obstack_init(&temp_obst);
+
+ type_int = make_atomic_type(ATOMIC_TYPE_INT, 0);
+ type_size_t = make_atomic_type(ATOMIC_TYPE_UINT, 0);
+ type_const_char = make_atomic_type(ATOMIC_TYPE_CHAR, TYPE_QUALIFIER_CONST);
+ type_void = make_atomic_type(ATOMIC_TYPE_VOID, 0);
+ type_string = make_pointer_type(type_const_char, 0);
}
void exit_parser(void)