diff options
Diffstat (limited to 'miniany/cc.c')
-rw-r--r-- | miniany/cc.c | 166 |
1 files changed, 135 insertions, 31 deletions
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 <cond> 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 ); |