From df1a8de0d0667f39b51cffa812dca780cc48bc14 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Fri, 29 Oct 2021 20:32:34 +0200 Subject: cc: - some work on function calls (with default EAX return and no params), also added a return statement - fix code generator for division (case when EDX is the operand resulting in endless loops) --- README.bootstrapping | 3 +- miniany/cc.c | 166 +++++++++++++++++++++++++++++++++++++++++---------- miniany/cc.wg | 8 +-- miniany/test1.c | 38 ++++++++++-- 4 files changed, 173 insertions(+), 42 deletions(-) diff --git a/README.bootstrapping b/README.bootstrapping index d68295b..6d77295 100644 --- a/README.bootstrapping +++ b/README.bootstrapping @@ -17,7 +17,8 @@ https://github.com/ras52/bootstrap bcompiler --------- -https://web.archive.org/web/20061108010907/http://www.rano.org/bcompiler.html +https://web.archive.org/web/20061108010907/ +http://www.rano.org/bcompiler.html https://github.com/certik/bcompiler asmc diff --git a/miniany/cc.c b/miniany/cc.c index c72d290..44cdd76 100644 --- a/miniany/cc.c +++ b/miniany/cc.c @@ -31,6 +31,7 @@ enum { S_ELSE, S_WHILE, S_DO, + S_RETURN, S_PUTINT, S_PUTCHAR, S_IDENT = 60, @@ -199,6 +200,12 @@ int keyword( char *ident ) return S_PUTCHAR; } break; + + case 'r': + if( strcmp( ident, "return" ) == 0 ) { + return S_RETURN; + } + break; case 'v': if( strcmp( ident, "void" ) == 0 ) { @@ -355,8 +362,9 @@ enum { struct Symbol { int class; /* class SYMBOL_CLASS_XXX */ char *name; /* name of the symbol */ - int type; /* type of variable when type is SYMBOL_CLASS_VARIABLE */ + int type; /* type of variable when class is SYMBOL_CLASS_VARIABLE */ struct Symbol *next; /* pointer to next symbol */ + int return_type; /* return type when class is SYMBOL_CLASS_FUNCTION */ }; struct Symbol *createSymbol( int class, char *s ) @@ -455,6 +463,7 @@ enum { A_LESS_OR_EQUALS, A_MORE, A_MORE_OR_EQUALS, + A_FUNC_CALL, A_ERR = 99 }; @@ -480,6 +489,11 @@ struct ASTnode *createASTnode( int op, struct ASTnode *left, struct ASTnode *rig return node; } +struct ASTnode *createASTunary( int op, struct ASTnode *left ) +{ + return createASTnode( op, left, NULL, 0, NULL ); +} + struct ASTnode *createASTbinary( int op, struct ASTnode *left, struct ASTnode *right ) { return createASTnode( op, left, right, 0, NULL ); @@ -751,15 +765,23 @@ int genLoadIdent( struct Generator *generator, struct Symbol *sym ) switch( sym->type ) { case S_INT: putreg( generator, reg ); + putstring( ", [" ); + putstring( sym->name ); + putstring( "]" ); + putnl( ); break; case S_CHAR: putlow8reg( generator, reg ); + putstring( ", [" ); + putstring( sym->name ); + putstring( "]" ); + putnl( ); + putstring( "and " ); + putreg( generator, reg ); + putstring( ", $FF" ); + putnl( ); break; } - putstring( ", [" ); - putstring( sym->name ); - putstring( "]" ); - putnl( ); return reg; } @@ -868,17 +890,18 @@ int genDiv( struct Generator *generator, int leftreg, int rightreg ) if( !generator->regFree[EDX] ) { genSaveReg( generator, EDX ); } - if( rightreg == EAX ) { + if( rightreg == EAX || rightreg == EDX ) { genSaveReg( generator, EBX ); - putstring( "mov ebx, eax" ); + putstring( "mov ebx, " ); + putreg( generator, rightreg ); putnl( ); - } + } putstring( "mov eax, " ); putreg( generator, leftreg ); putnl( ); putstring( "mov edx, 0" ); putnl( ); - if( rightreg == EAX ) { + if( rightreg == EAX || rightreg == EDX ) { reg = genBinary( "div", generator, EAX, EBX, 1 ); genRestoreReg( generator, EBX ); } else { @@ -920,6 +943,15 @@ int genCompare( char *op, struct Generator *generator, int leftreg, int rightreg return leftreg; } +int genFuncCall( struct Generator *generator, char *name ) +{ + putstring( "call " ); + putstring( name ); + putnl( ); + + return EAX; +} + int generateFromAST( struct Generator *generator, struct ASTnode *node, int inreg ) { int leftreg, rightreg, reg; @@ -976,11 +1008,16 @@ int generateFromAST( struct Generator *generator, struct ASTnode *node, int inre case A_MORE_OR_EQUALS: reg = genCompare( "setge", generator, leftreg, rightreg ); break; + case A_FUNC_CALL: + reg = genFuncCall( generator, node->sym->name ); + break; default: + scannerPrintErrorHeader( generator->scanner ); + putstring( "unhandled AST node operation '" ); putint( node->op ); - putstring( "?" ); - break; - + putstring( "'" ); + putnl( ); + exit( EXIT_FAILURE ); } return reg; @@ -1182,6 +1219,24 @@ int parserOperatorPrecedence( struct Parser *parser, int operator ) return precedence; } +struct ASTnode *parseExpression( struct Parser *parser, int level ); + +struct ASTnode *parseFunctionCall( struct Parser *parser, struct Symbol *sym ) +{ + struct ASTnode *node, *left; + + parserExpect( parser, S_LPAREN, "(" ); + /* TODO: parse parameters as expressions: + left = parseExpression( parser, 0 ); + */ + left = NULL; + parserExpect( parser, S_RPAREN, ")" ); + node = createASTunary( A_FUNC_CALL, left ); + node->sym = sym; + + return node; +} + struct ASTnode *parseExpression( struct Parser *parser, int level ) { struct ASTnode *left, *right; @@ -1197,6 +1252,7 @@ struct ASTnode *parseExpression( struct Parser *parser, int level ) if( parser->token == S_NUM ) { left = createASTleafInt( A_INT_LITERAL, parser->scanner->num ); + parser->token = getToken( parser->scanner ); } else if( parser->token == S_IDENT ) { sym = getSymbol( parser->global_scope, parser->scanner->ident ); if( sym == NULL ) { @@ -1207,7 +1263,23 @@ struct ASTnode *parseExpression( struct Parser *parser, int level ) putnl( ); exit( EXIT_FAILURE ); } - left = createASTleafSym( A_IDENT, sym ); + if( sym->class == SYMBOL_CLASS_VARIABLE ) { + left = createASTleafSym( A_IDENT, sym ); + parser->token = getToken( parser->scanner ); + } else if( sym->class == SYMBOL_CLASS_FUNCTION ) { + parser->token = getToken( parser->scanner ); + left = parseFunctionCall( parser, sym ); + } else { + left = NULL; + scannerPrintErrorHeader( parser->scanner ); + putstring( "unknown class '" ); + putint( sym->class ); + putstring( "' of identifier '" ); + putstring( parser->scanner->ident ); + putstring( "' in expression" ); + putnl( ); + exit( EXIT_FAILURE ); + } } else { left = NULL; scannerPrintErrorHeader( parser->scanner ); @@ -1218,7 +1290,6 @@ struct ASTnode *parseExpression( struct Parser *parser, int level ) exit( EXIT_FAILURE ); } - parser->token = getToken( parser->scanner ); if( parser->token == S_EOI || parser->token == S_SEMICOLON || parser->token == S_RPAREN ) { return left; } @@ -1240,7 +1311,7 @@ struct ASTnode *parseExpression( struct Parser *parser, int level ) int parseType( struct Compiler *compiler ) { struct Parser *parser; - int type; + int type = S_ERR; parser = compiler->parser; if( parser->token == S_INT || parser->token == S_CHAR || parser->token == S_VOID ) { @@ -1298,15 +1369,31 @@ void parseAssignment( struct Compiler *compiler ) putnl( ); exit( EXIT_FAILURE ); } - right = createASTleafSym( A_LVIDENT, sym ); - parserExpect( parser, S_ASSIGN, "=" ); - left = parseExpression( parser, 0 ); - parserExpect( parser, S_SEMICOLON, ";" ); - - node = createASTbinary( A_ASSIGN, left, right ); - generateFromAST( compiler->generator, node, NOREG ); - genFreeAllRegs( compiler->generator ); - freeASTnode( node ); + if( sym->class == SYMBOL_CLASS_VARIABLE ) { + right = createASTleafSym( A_LVIDENT, sym ); + parserExpect( parser, S_ASSIGN, "=" ); + left = parseExpression( parser, 0 ); + parserExpect( parser, S_SEMICOLON, ";" ); + + node = createASTbinary( A_ASSIGN, left, right ); + generateFromAST( compiler->generator, node, NOREG ); + genFreeAllRegs( compiler->generator ); + freeASTnode( node ); + } else if( sym->class == SYMBOL_CLASS_FUNCTION ) { + node = parseFunctionCall( parser, sym ); + parserExpect( parser, S_SEMICOLON, ";" ); + generateFromAST( compiler->generator, node, NOREG ); + freeASTnode( node ); + } else { + scannerPrintErrorHeader( parser->scanner ); + putstring( "symbol '" ); + putstring( parser->scanner->ident ); + putstring( "' has unexpected class '" ); + putint( sym->class ); + putstring( "'" ); + putnl( ); + exit( EXIT_FAILURE ); + } } void parsePutint( struct Compiler *compiler ) @@ -1378,6 +1465,7 @@ void parseIf( struct Compiler *compiler ) putstring( "; if then" ); putnl( ); } generateFromAST( compiler->generator, node, NOREG ); + freeASTnode( node ); /* TODO: this should be condensed and optimized for the normal path * (rare ifs, invert the condition, jmpXX directly */ putstring( "cmp al, 0" ); putnl( ); @@ -1424,6 +1512,7 @@ void parseWhile( struct Compiler *compiler ) label2 = genGetLabel( compiler, compiler->parser->global_scope ); putstring( label2 ); putchar( ':' ); putnl( ); generateFromAST( compiler->generator, node, NOREG ); + freeASTnode( node ); putstring( "cmp al, 0" ); putnl( ); genFreeAllRegs( compiler->generator ); label1 = genGetLabel( compiler, compiler->parser->global_scope ); @@ -1460,6 +1549,7 @@ void parseDo( struct Compiler *compiler ) parserExpect( parser, S_LPAREN, "(" ); node = parseExpression( parser, 0 ); generateFromAST( compiler->generator, node, NOREG ); + freeASTnode( node ); putstring( "cmp al, 0" ); putnl( ); genFreeAllRegs( compiler->generator ); putstring( "jne " ); putstring( label1 ); putnl( ); @@ -1468,6 +1558,19 @@ void parseDo( struct Compiler *compiler ) free( label1 ); } +void parseReturn( struct Compiler *compiler ) +{ + struct Parser *parser; + struct ASTnode *node; + + parser = compiler->parser; + parserExpect( parser, S_RETURN, "return" ); + node = parseExpression( parser, 0 ); + generateFromAST( compiler->generator, node, NOREG ); + freeASTnode( node ); + parserExpect( parser, S_SEMICOLON, ";" ); +} + void parseStatement( struct Compiler *compiler ) { struct Parser *parser; @@ -1487,6 +1590,8 @@ void parseStatement( struct Compiler *compiler ) parseWhile( compiler ); } else if( parser->token == S_DO ) { parseDo( compiler ); + } else if( parser->token == S_RETURN ) { + parseReturn( compiler ); } else if( parser->token == S_RBRACE || parser->token == S_EOI ) { return; } else { @@ -1520,18 +1625,13 @@ void parseFunctionDeclaration( struct Compiler *compiler ) parser = compiler->parser; type = parseType( compiler ); - if( type != S_VOID ) { - scannerPrintErrorHeader( parser->scanner ); - putstring( "expected void as return value of a function declaration" ); - putnl( ); - exit( EXIT_FAILURE ); - } parserExpect( parser, S_IDENT, "identifier" ); sym = getSymbol( parser->global_scope, parser->scanner->ident ); if( sym == NULL ) { sym = createSymbol( SYMBOL_CLASS_FUNCTION, parser->scanner->ident ); insertSymbol( parser->global_scope, sym ); + sym->return_type = type; } else { scannerPrintErrorHeader( parser->scanner ); putstring( "duplicate global symbol '" ); @@ -1551,10 +1651,12 @@ void parseFunctionDeclaration( struct Compiler *compiler ) putstring( "push ebp" ); putnl( ); putstring( "mov ebp, esp" ); putnl( ); parserExpect( parser, S_LPAREN, "(" ); + /* TODO: parse parameter list */ parserExpect( parser, S_RPAREN, ")" ); parseStatementBlock( compiler ); putstring( "pop ebp" ); putnl( ); putstring( "ret" ); putnl( ); + genFreeAllRegs( compiler->generator ); } /* compiler */ @@ -1589,7 +1691,9 @@ int main( int argc, char **argv ) /* compiler->generator->debug = 1; */ genPrologue( compiler ); compiler->parser->token = getToken( compiler->parser->scanner ); - parseFunctionDeclaration( compiler ); + while( compiler->parser->token != S_EOI ) { + parseFunctionDeclaration( compiler ); + } genEpilogue( compiler ); freeCompiler( compiler ); diff --git a/miniany/cc.wg b/miniany/cc.wg index 2a0ad6d..352d664 100644 --- a/miniany/cc.wg +++ b/miniany/cc.wg @@ -29,9 +29,9 @@ WordGrinder dumpfile v3: this is a text file; diff me! .clipboard.margin: 0 .clipboard.viewmode: 1 .clipboard.wordcount: 6 -.documents.1.co: 7 -.documents.1.cp: 31 -.documents.1.cw: 25 +.documents.1.co: 6 +.documents.1.cp: 38 +.documents.1.cw: 8 .documents.1.margin: 0 .documents.1.name: "main" .documents.1.sticky_selection: false @@ -141,7 +141,7 @@ WordGrinder dumpfile v3: this is a text file; diff me! .menu.accelerators.ZU: "UP" .menu.accelerators.ZWL: "^LEFT" .menu.accelerators.ZWR: "^RIGHT" -.name: "/media/sd/abaumann/projects/compilertests/miniany/cc.wg" +.name: "/home/abaumann/projects/compilertests/miniany/cc.wg" .replacetext: "" .statusbar: true .current: 1 diff --git a/miniany/test1.c b/miniany/test1.c index 30650f0..4c919ce 100644 --- a/miniany/test1.c +++ b/miniany/test1.c @@ -1,8 +1,23 @@ /* test1 */ +/* TODO: check void (no return allowed) and check for int (in this case it is required) */ +int f( ) +{ + return 42; +} + +void f2( ) +{ + putint( 44 ); +} + void main( ) { - char c; + // TODO: allow enumeration of variable declarations + char c1; + char c2; + char c3; + char c4; int i; int j; int k; @@ -31,15 +46,26 @@ void main( ) i = 5; while( i > 0 ) { putint( i ); - i = i-1; + i = i - 1; } i = 1; do { putint( i ); - i = i+1; + i = i + 1; } while( i <= 5 ); - c = 41; - c = c + 1; - putchar( c ); + c1 = 422; // TODO: wrong narrowing from int const to char type, must be catched + c1 = 41; + c2 = c1 + 1; + c3 = c2 + 1; + c4 = c3 + 1; + putchar( c1 ); + putchar( c2 ); + putchar( c3 ); + putchar( c4 ); + i = f( ); + putint( i ); + f2( ); + // TODO: disallow this assignment, LHS is a function, RHS is an integer literal + //f = 1; } -- cgit v1.2.3-54-g00ecf