AstNode* ast_binop(int op, AstNode* left, AstNode* right);
AstNode* ast_unop(int op, AstNode* operand);
-// TODO: Add a store operation handler
+AstNode* ast_store(AstNode* dest, AstNode* value);
AstNode* ast_fieldref(Parser* p, AstNode* record, char* fname);
AstNode* ast_index(Parser* p, AstNode* array, AstNode* index);
AstNode* ast_if(AstNode* cond, AstNode* br1, AstNode* br2);
AstNode* ast_return(AstNode* expr);
-void ast_print(AstNode* expr);
+void ast_print(Parser* p, AstNode* expr);
/* Backend Code Generation and Base Type Definitions
*****************************************************************************/
case BOOL:
case INT:
case REAL:
- case IDENT:
ret = true;
break;
a->hdr.type = &BoolType;
break;
- // case IS: break;
-
default:
assert(!"not a valid op");
break;
return ret;
}
+AstNode* ast_store(AstNode* dest, AstNode* value)
+{
+ /* TODO: validate left-hand side is assignable */
+ return ast_new('=', &VoidType, dest, value, NULL);
+}
+
+static Field* get_field(Parser* p, Type* type, char* name)
+{
+ Field* curr = type->fields;
+ while (curr)
+ {
+ if (curr->name && !strcmp(curr->name, name))
+ {
+ break;
+ }
+ curr = curr->next;
+ }
+ if (!curr)
+ {
+ error(p, "record has no such field '%s'\n", name);
+ }
+ return curr;
+}
+
AstNode* ast_fieldref(Parser* p, AstNode* record, char* fname)
{
- /* TODO: actually access the field and check that it exists */
+ Field* field = get_field(p, record->hdr.type, fname);
+ AstNode* offset = ast_int(field->offset);
+ if (record->hdr.code == '.')
+ {
+ /* accumulate the offset into an existing record access */
+ record->links[1] = ast_binop('+', record->links[1], offset);
+ record->hdr.type = field->type;
+ }
+ else
+ {
+ /* create a new record access node */
+ record = ast_new('.', field->type, record, offset, NULL);
+ }
return record;
}
AstNode* ast_index(Parser* p, AstNode* array, AstNode* index)
{
- /* TODO: actually access the array index */
- /*
- * offset = index * sizeof(base)
- * array->type = array->type->base;
- * return new ast(ARRAY, base, offset)
- */
- return array;
+ if (ast_isconst(index) && ast_asint(p, index) >= array->hdr.type->size)
+ {
+ error(p, "constant array index out of bounds");
+ }
+ return ast_new('[', array->hdr.type->base, array, index, NULL);
}
AstNode* ast_block(void)
void ast_block_add(AstNode* blk, AstNode* stmt)
{
- /* TODO: append to linked list */
- (void)blk, (void)stmt;
+ assert(blk->hdr.code == BEGIN);
+ if (!blk->links[0])
+ {
+ blk->links[0] = stmt;
+ blk->links[1] = stmt;
+ }
+ else
+ {
+ blk->links[1]->hdr.next = stmt;
+ blk->links[1] = stmt;
+ }
}
AstNode* ast_call(AstNode* func)
return ast_new(RETURN, &VoidType, expr, NULL, NULL);
}
-void ast_print(AstNode* node)
+static void print_indent(int indent, char* str)
+{
+ /* print the indent */
+ for (int i = 0; i < indent; i++)
+ {
+ printf(" ");
+ }
+ if (str)
+ {
+ printf("%s", str);
+ }
+}
+
+static void print_opcode(AstNode* node)
+{
+ int op = node->hdr.code;
+ if (op < 256)
+ {
+ printf("(%c\n", op);
+ }
+ else
+ {
+ printf("(%d\n", op);
+ }
+}
+
+static void print(Parser* p, AstNode* node, int indent)
{
assert(node);
+ print_indent(indent, NULL);
+
+ /* now print the data */
switch(node->hdr.code)
{
case BOOL:
break;
case IDENT:
- printf("S:%lld", ((AstValue*)node)->val.i);
+ {
+ Symbol* s = symbol_getbyid(p, ((AstValue*)node)->val.i);
+ printf("S:%s", s->name);
+ }
+ break;
+
+ case '.':
+ printf("(field-ref)");
+ break;
+
+ case '[':
+ printf("(array-index)");
+ break;
+
+ case BEGIN:
+ {
+ printf("(begin\n");
+ for (AstNode* curr = node->links[0]; curr; curr = curr->hdr.next)
+ {
+ print(p, curr, indent+1);
+ }
+ printf(")");
+ }
break;
default:
if (node->links[1])
{
- printf("(binop)");
+ print_opcode(node);
+ print(p, node->links[0], indent+1);
+ print(p, node->links[1], indent+1);
+ print_indent(indent, ")");
}
else
{
- printf("(%d ", node->hdr.code);
- ast_print(node->links[0]);
- printf(")");
+ print_opcode(node);
+ print(p, node->links[0], indent+1);
+ print_indent(indent, ")");
}
break;
}
+ puts("");
+}
+
+void ast_print(Parser* p, AstNode* node)
+{
+ print(p, node, 0);
}
{
AstNode* right = expression(p);
check_types(p, expr, right);
- expr = ast_binop('=', expr, right);
+ expr = ast_store(expr, right);
}
expect(p, ';');
ast_block_add(block, expr);
sym = symbol_new(p, 0, name, SYM_CONST, export);
expect(p, '=');
sym->value = expression(p);
- ast_print(sym->value);
- puts("");
}
while (matches(p, IDENT));
+
EXIT_RULE();
}
// proc_decl(p);
// }
-// codegen_startproc(p, NULL);
if (accept(p, BEGIN))
{
-// codegen_imports(p);
AstNode* block = statement_seq(p);
- ast_print(block);
- puts("");
+ ast_print(p, block);
expect(p, END);
}
-// codegen_endproc(p);
if (!matches(p, END_FILE))
{
char* fcontents = file_load(fname);
Parser* p = &(Parser){
.name = NULL,
-// .scope = &RealSym,
.file = &(LexFile){
.path = fname,
.fbeg = fcontents,
symbol_new(p, 0, "Int", SYM_TYPE, 0)->type = &IntType;
symbol_new(p, 0, "Real", SYM_TYPE, 0)->type = &RealType;
symbol_new(p, 0, "String", SYM_TYPE, 0)->type = &StringType;
-
-// codegen_startmod(p);
module(p);
-// codegen_main(p);
-// codegen_endmod(p);
}
/* Grammar Unit Tests