From 3d41b8813db0ebe45ce7d0c54604554812ddb484 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Fri, 14 Aug 2020 21:31:06 +0200 Subject: started handling value parameters for procedures - asm386 handles also negative numbers (for negative offsets for parameters on stack) - parameter handling in stdcall style (procedure handles all of the stack operations) --- ecomp-c/asm-i386.c | 17 ++- ecomp-c/ec.c | 170 ++++++++++++++++++------ ecomp-c/minie.ebnf | 9 +- ecomp-c/test1.e | 19 ++- ecomp-c/tests/procedure_call_value_parameters.e | 20 +++ 5 files changed, 187 insertions(+), 48 deletions(-) create mode 100644 ecomp-c/tests/procedure_call_value_parameters.e diff --git a/ecomp-c/asm-i386.c b/ecomp-c/asm-i386.c index 25a1e86..c9de15a 100644 --- a/ecomp-c/asm-i386.c +++ b/ecomp-c/asm-i386.c @@ -262,7 +262,12 @@ static void skipWhite( void ) static void number( void ) { int n = 0; + int negative = 0; + if( look == '-' ) { + negative = 1; + look = getChar( ); + } if( isDigit( look ) ) { num = look - '0'; look = getChar( ); @@ -276,6 +281,9 @@ static void number( void ) } sym = S_number; } + if( negative ) { + num = ~num + 1; + } } static void hexnumber( void ) @@ -418,7 +426,14 @@ static S_Symbol getSym( void ) break; case '-': look = getChar( ); - s = S_minus; + if( look >= '0' && look <= '9' ) { + ungetChar( look ); + s = S_number; + look = '-'; + number( ); + } else { + s = S_minus; + } break; case '+': look = getChar( ); diff --git a/ecomp-c/ec.c b/ecomp-c/ec.c index 5b72bfc..5d42355 100644 --- a/ecomp-c/ec.c +++ b/ecomp-c/ec.c @@ -692,7 +692,7 @@ typedef struct Scope { int label_no; struct Symbol *symbol; struct Scope *parent; - int size_locals; + int nof_symbols; } Scope; static Scope *global_scope; @@ -706,6 +706,7 @@ static Scope *create_scope( Scope *parent, char *name ) scope->symbol = NULL; scope->parent = parent; scope->label_no = 0; + scope->nof_symbols = 0; return scope; } @@ -805,6 +806,7 @@ static Symbol *insert_symbol( Scope *scope, char *name, SymbolClass class ) sym->intarr_value = NULL; sym->label = NULL; scope->symbol = sym; + scope->nof_symbols++; return sym; } @@ -1541,6 +1543,22 @@ static void parseWhileStatement( Scope *scope ) free( jump_label1 ); } +static void parseParameterList( Scope *scope ) +{ + ExpressionNode *node; + + Expect( S_lparen ); + do { + node = parseExpression( scope ); + if( sym == S_comma ) { + sym = getSym( ); + } + } while( sym != S_rparen ); + Expect( S_rparen ); + + (void)node; +} + static void parseStatement( Scope *scope ) { Symbol *symbol; @@ -1558,6 +1576,9 @@ static void parseStatement( Scope *scope ) Abort( "Unknown indentifier '%s'", ident ); } if( symbol->class == SYMBOL_CLASS_PROCEDURE_TYPE ) { + if( sym == S_lparen ) { + parseParameterList( scope ); + } Emit( "call %s\n", symbol->label ); } else { parseAssignment( scope ); @@ -1990,10 +2011,42 @@ static void parseProcedureDeclarationBlock( Scope *scope ) } } -static void parseProcedureBlock( Scope *scope ) +static void parseParameterDeclaration( Scope *scope ) +{ + Symbol *symbol; + + Expect( S_ident ); + symbol = insert_symbol( scope, ident, SYMBOL_CLASS_VARIABLE ); + + /* TODO: allocate size for parameters on stack, make sure they + * are allocated on the other side of the stack + */ + + Expect( S_colon ); + + symbol->type = parseType( scope ); +} + +static void parseParameterDeclarationList( Scope *scope ) +{ + Expect( S_lparen ); + do { + if( sym == S_ident ) { + parseParameterDeclaration( scope ); + if( sym == S_comma ) { + sym = getSym( ); + } + } + } while( sym != S_rparen ); + Expect( S_rparen ); +} + +static void parseProcedureDeclaration( Scope *scope ) { char *procedure_label; Symbol *symbol; + int size_locals; + int size_params; Expect( S_procedure ); Expect( S_ident ); @@ -2008,11 +2061,45 @@ static void parseProcedureBlock( Scope *scope ) /* TODO: check, if parameter lists and return values match */ } - Expect( S_semicolon ); + /* local scope holding all local defitions */ + symbol->scope = create_scope( scope, symbol->name ); + if( sym == S_semicolon ) { + /* no parameters */ + sym = getSym( ); + size_params = 0; + } else if( sym == S_lparen ) { + + Symbol *param; + int offset; + + parseParameterDeclarationList( symbol->scope ); + if( sym == S_semicolon ) { + /* forward declaration */ + sym = getSym( ); + } + + param = symbol->scope->symbol; + + size_params = 0; + offset = 0; + while( param != NULL ) { + if( param->class == SYMBOL_CLASS_VARIABLE ) { + int size = get_size( param ); + size_params += size; + param->offset = offset - size; + Emit( "; param %s, offset: %d, size: %d\n", + param->name, param->offset, size ); + offset -= size; + } + param = param->next; + } + } + + /* procedure body */ if( sym == S_const || sym == S_var || sym == S_begin ) { - Symbol *sym; + Symbol *local, *param_or_local; int offset; Emit( "; PROC %s\n", symbol->name ); @@ -2023,9 +2110,6 @@ static void parseProcedureBlock( Scope *scope ) Emit( "push ebp\n" ); Emit( "push esp\n" ); Emit( "pop ebp\n" ); - - /* local scope holding all local defitions */ - symbol->scope = create_scope( scope, symbol->name ); /* TODO: parse parameters, assign parameter values to * local variables (when passed by value) or set @@ -2034,66 +2118,66 @@ static void parseProcedureBlock( Scope *scope ) parseProcedureDeclarationBlock( symbol->scope ); /* compute sizes of all locals */ + size_locals = 0; offset = 0; - scope->size_locals = 0; - sym = symbol->scope->symbol; - while( sym != NULL ) { - if( sym->class == SYMBOL_CLASS_VARIABLE ) { - int size = get_size( sym ); - scope->size_locals += size; - sym->offset = offset + size; + local = symbol->scope->symbol; + while( local != NULL ) { + if( local->class == SYMBOL_CLASS_VARIABLE && local->offset == 0 ) { + int size = get_size( local ); + size_locals += size; + local->offset = offset + size; Emit( "; local %s, offset: %d, size: %d\n", - sym->name, sym->offset, size ); + local->name, local->offset, size ); offset += size; } - sym = sym->next; + local = local->next; } - /* reserve space on stack */ - if( scope->size_locals > 0 ) { - Emit( "mov eax, %d\n", scope->size_locals ); + /* reserve space on stack for locals */ + if( size_locals > 0 ) { + Emit( "mov eax, %d\n", size_locals ); Emit( "sub esp, eax\n" ); } /* initialize local variables (sort of reserve_initialize_local) * at runtime (every time the stack is created for that procedure) */ - sym = symbol->scope->symbol; - while( sym != NULL ) { - if( sym->class == SYMBOL_CLASS_VARIABLE ) { + param_or_local = symbol->scope->symbol; + while( param_or_local != NULL ) { + if( param_or_local->class == SYMBOL_CLASS_VARIABLE ) { /* TODO: use type here! */ - int size = get_size( sym ); - if( sym->type == integer_type || sym->type == boolean_type ) { + int size = get_size( param_or_local ); + if( param_or_local->type == integer_type || param_or_local->type == boolean_type ) { switch( size ) { case 4: /* TODO: cleanup local global variable access */ Emit( "push ebp\n" ); Emit( "pop ebx\n" ); - Emit( "mov eax, %d\n", sym->offset ); + Emit( "mov eax, %d\n", param_or_local->offset ); Emit( "sub ebx, eax\n" ); - Emit( "mov eax, %d\n", sym->integer_value ); + Emit( "mov eax, %d\n", param_or_local->integer_value ); Emit( "mov [ebx], eax\n" ); break; case 1: /* TODO: cleanup local global variable access */ Emit( "push ebp\n" ); Emit( "pop ebx\n" ); - Emit( "mov eax, %d\n", sym->offset ); + Emit( "mov eax, %d\n", param_or_local->offset ); Emit( "sub ebx, eax\n" ); - Emit( "mov eax, %d\n", sym->boolean_value ); + Emit( "mov eax, %d\n", param_or_local->boolean_value ); Emit( "mov [ebx], al\n" ); break; default: - Abort( "Unhandled case when initializing local variable '%s' of primitive type on stack", sym->name ); + Abort( "Unhandled case when initializing local variable '%s' of primitive type on stack", param_or_local->name ); } - } else if( sym->type->class == SYMBOL_CLASS_ARRAY_TYPE ) { + } else if( param_or_local->type->class == SYMBOL_CLASS_ARRAY_TYPE ) { /* TODO: we would need an internal memset here * memset( ebp + offset, get_size, 0 ) */ } else { - Abort( "Unhandled case when initializing local variable '%s' of complex type on stack", sym->name ); + Abort( "Unhandled case when initializing local variable '%s' of complex type on stack", param_or_local->name ); } } - sym = sym->next; + param_or_local = param_or_local->next; } /* TODO: allocate space on stack for local variables (and @@ -2103,19 +2187,25 @@ static void parseProcedureBlock( Scope *scope ) parseStatementBlock( symbol->scope ); - /* discard locals, reset base pointer */ - - if( scope->size_locals > 0 ) { - Emit( "mov eax, %d\n", scope->size_locals ); + /* discard locals, discard params, reset base pointer */ + if( size_locals + size_params > 0 ) { + Emit( "mov eax, %d\n", size_locals + size_params ); Emit( "add esp, eax\n" ); } - free_scope( symbol->scope ); - Emit( "pop ebp\n" ); Emit( "ret\n" ); } + + free_scope( symbol->scope ); +} + +static void parseProcedureBlock( Scope *scope ) +{ + while( sym == S_procedure ) { + parseProcedureDeclaration( scope ); + } } static void parseDeclarationBlock( Scope *scope ) @@ -2126,10 +2216,10 @@ static void parseDeclarationBlock( Scope *scope ) if( sym == S_var ) { parseVariableBlock( scope ); } - while( sym == S_procedure ) { + if( sym == S_procedure ) { parseProcedureBlock( scope ); } -} +} static void parseModule( Scope *scope ) { diff --git a/ecomp-c/minie.ebnf b/ecomp-c/minie.ebnf index 484572d..be68ba8 100644 --- a/ecomp-c/minie.ebnf +++ b/ecomp-c/minie.ebnf @@ -17,7 +17,8 @@ Expression = SimpleExpression [ RelationalOperator SimpleExpression ] . Assignment = Identifier [ "[" Expression "]" ] ":=" Expression . IfStatement = "if" Expression "do" StatementSequence "else" StatementSequence "end" . WhileStatement = "while" Expression "do" StatementSequence "end" . -ProcedureCall = Identifier . +ParameterList = "(" Expression { "," Expression } ")" . +ProcedureCall = Identifier [ ParameterList ] . Statement = Assignment | IfStatement | WhileStatement | ProcedureCall . StatementSequence = Statement { ";" Statement } . StatementBlock = "begin" StatementSequence "end" . @@ -29,8 +30,10 @@ ConstDeclaration = Identifier { "," Identifier } ":" Type "=" ConstExpression . ConstBlock = "const" { ConstDeclaration ";" } . VariableDeclaration = Identifier { "," Identifier } ":" Type [ ":=" ConstExpression ] . VariableBlock = "var" { VariableDeclaration ";" } . -ProcedureDeclaration = "procedure" Identifier ";" ProcedureDeclarationBlock StatementBlock . -ProcedureBlock = { ProcedureDeclaration } . +ParameterDeclaration = Identifier ":" Type . +ParamaterDeclarationList = "(" ParameterDeclaration { "," ParameterDeclaration } ")" . +ProcedureDeclaration = "procedure" Identifier [ ParamaterDeclarationList ] ";" ProcedureDeclarationBlock StatementBlock . ProcedureDeclarationBlock = [ ConstBlock ] [ VariableBlock ] . +ProcedureBlock = { ProcedureDeclaration } . DeclarationBlock = [ ConstBlock ] [ VariableBlock ] [ ProcedureBlock ] . Module = "module" Identifier ";" DeclarationBlock StatementBlock . diff --git a/ecomp-c/test1.e b/ecomp-c/test1.e index 49418db..59ec90a 100644 --- a/ecomp-c/test1.e +++ b/ecomp-c/test1.e @@ -32,17 +32,28 @@ var s2 : array 10 of character := "hello"; a1 : array 10 of integer; -procedure B; +procedure B( n : integer, m : integer ); procedure A; +const + N : integer = 10; + S : array N of character = "local"; +var + s : array N of character := S; + begin a1[5] := 43; - B; + s[0] := 'L'; + B( a1[5], 7 ); end -procedure B; +procedure B( n : integer, m : integer ); +var + x : integer; + begin - a1[4] := 44; + x := n + m; + a1[4] := x; end begin diff --git a/ecomp-c/tests/procedure_call_value_parameters.e b/ecomp-c/tests/procedure_call_value_parameters.e new file mode 100644 index 0000000..3b100ed --- /dev/null +++ b/ecomp-c/tests/procedure_call_value_parameters.e @@ -0,0 +1,20 @@ +/* + * procedure call with value parameters + */ + +module procedure_call_value_parameters; + +var + i : integer := 0; + +procedure proc( x : integer ); +var + l : integer; +begin + l := x; + i := x; +end + +begin + proc( 42 ); +end -- cgit v1.2.3-54-g00ecf