From 6c6fe33b224dc3342d8d8fc5fc2d27777eb55b89 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Fri, 18 Sep 2020 20:48:13 +0200 Subject: some work on functions --- ecomp-c/ec.c | 112 ++++++++++++++++++++++++++++++++++++++++++++--------- ecomp-c/minie.ebnf | 9 ++--- ecomp-c/test1.e | 29 +++++++++++--- 3 files changed, 120 insertions(+), 30 deletions(-) diff --git a/ecomp-c/ec.c b/ecomp-c/ec.c index 1fc0dd6..5ec97cc 100644 --- a/ecomp-c/ec.c +++ b/ecomp-c/ec.c @@ -17,7 +17,7 @@ enum { }; static int DEBUG_GETCHAR = 0; -static int DEBUG_SCANNER = 0; +static int DEBUG_SCANNER = 1; typedef enum { BINARY_FORMAT_EMUL = 0, @@ -45,6 +45,8 @@ typedef enum { S_else, S_while, S_procedure, + S_function, + S_return, S_div, S_mod, S_not, @@ -88,6 +90,8 @@ static char *symname[S_eof+1] = { "else", "while", "procedure", + "function", + "return", "div", "mod", "not", @@ -405,6 +409,14 @@ static S_Symbol getSym( void ) s = S_ident; } break; + case 'f': + identifier( ); + if( strcmp( ident, "function" ) == 0 ) { + s = S_function; + } else { + s = S_ident; + } + break; case 'i': identifier( ); if( strcmp( ident, "if" ) == 0 ) { @@ -449,6 +461,14 @@ static S_Symbol getSym( void ) s = S_ident; } break; + case 'r': + identifier( ); + if( strcmp( ident, "return" ) == 0 ) { + s = S_return; + } else { + s = S_ident; + } + break; case 'v': identifier( ); if( strcmp( ident, "var" ) == 0 ) { @@ -465,14 +485,12 @@ static S_Symbol getSym( void ) s = S_ident; } break; - case 'f': case 'g': case 'h': case 'j': case 'k': case 'l': case 'q': - case 'r': case 's': case 't': case 'u': @@ -678,10 +696,12 @@ typedef struct Symbol { int offset; /* array type */ int dim; - /* procedure type */ + /* procedure/function type */ char *label; struct Scope *scope; struct Symbol *param; + int is_func; + struct Symbol *return_type; } Symbol; static Symbol *integer_type; @@ -805,6 +825,8 @@ static Symbol *create_symbol( char *name, SymbolClass class ) symbol->type = NULL; symbol->label = NULL; symbol->param = NULL; + symbol->is_func = 0; + symbol->return_type = NULL; return symbol; } @@ -1235,6 +1257,7 @@ static void emit_expression_code( ExpressionNode *node, Scope *scope ) } static ExpressionNode *parseExpression( Scope *scope ); +static void parseParameterList( Scope *scope, ExpressionNodeList *list ); static ExpressionNode *parseFactor( Scope *scope ) { @@ -1292,6 +1315,16 @@ static ExpressionNode *parseFactor( Scope *scope ) node->symbol = symbol; node->actual_type = symbol->type; } + } else if( symbol->class == SYMBOL_CLASS_PROCEDURE_TYPE ) { + sym = getSym( ); + if( !symbol->is_func ) { + Abort( "Expecting function and not procedure" ); + } + /* TODO: parse parameters as in a procedure call + parseProcedureCall + then add result into expression, problem here is + we generate code directly in parseProcedureCall and + not an ADT before, must refactor */ } else { Abort( "'%s' is the name for a type and not a constant or variable as expected", ident ); } @@ -1634,7 +1667,7 @@ static void parseProcedureCall( Scope *scope ) } nof_actual_params = 0; - if( sym == S_lparen ) { + if( sym == S_lparen ) { parseParameterList( scope, &list ); node = list.head; @@ -1726,20 +1759,13 @@ static void parseStatementSequence( Scope *scope ) } while( sym == S_semicolon ) { sym = getSym( ); - if( sym == S_end || sym == S_else ) { + if( sym == S_end || sym == S_else || sym == S_return ) { return; } parseStatement( scope ); } } -static void parseStatementBlock( Scope *scope ) -{ - Expect( S_begin ); - parseStatementSequence( scope ); - Expect( S_end ); -} - /* TODO: implement simple expression and later complex expression */ static ExpressionNode *parseConstExpression( Scope *scope ) { @@ -2171,10 +2197,11 @@ static void parseProcedureDeclaration( Scope *scope ) Symbol *symbol; int size_locals; int size_params = 0; - - Expect( S_procedure ); + S_Symbol proc_sym = sym; + + sym = getSym( ); if( sym != S_ident ) { - Abort( "Expecting name of a procedure after 'procedure'" ); + Abort( "Expecting name of a procedure or function after '%s'", symname[proc_sym] ); } symbol = get_symbol( scope, ident ); @@ -2183,6 +2210,11 @@ static void parseProcedureDeclaration( Scope *scope ) procedure_label = get_scoped_label( scope, ident ); symbol->label = AllocateAndCopyStr( procedure_label ); free( procedure_label ); + if( proc_sym == S_procedure ) { + symbol->is_func = 0; + } else if( proc_sym == S_function ) { + symbol->is_func = 1; + } } else if( symbol->class == SYMBOL_CLASS_PROCEDURE_TYPE ) { /* TODO: check, if parameter lists and return values match */ } @@ -2201,6 +2233,16 @@ static void parseProcedureDeclaration( Scope *scope ) int offset; parseParameterDeclarationList( symbol->scope ); + + if( sym == S_colon ) { + if( symbol->is_func ) { + symbol->return_type = parseType( scope ); + sym = getSym( ); + } else { + Abort( "A procedure cannot have a return type" ); + } + } + if( sym == S_semicolon ) { /* forward declaration */ sym = getSym( ); @@ -2216,6 +2258,10 @@ static void parseProcedureDeclaration( Scope *scope ) while( param != NULL ) { if( param->class == SYMBOL_CLASS_VARIABLE ) { int size = get_size( param ); + if( size < 4 ) { + /* parameters on stack are always 4 bytes */ + size = 4; + } size_params += size; param->offset = offset - size; Emit( "; param %s, offset: %d, size: %d\n", @@ -2269,10 +2315,20 @@ static void parseProcedureDeclaration( Scope *scope ) } param = param->next; } + } + } else if( sym == S_colon ) { + if( symbol->is_func ) { + symbol->return_type = parseType( scope ); + } else { + Abort( "A procedure cannot have a return type" ); } } else { Abort( "Semicolon expected" ); } + + if( symbol->is_func && symbol->return_type == NULL ) { + Abort( "A function must have a return type" ); + } /* procedure body */ if( sym == S_const || sym == S_var || sym == S_begin ) { @@ -2363,7 +2419,23 @@ static void parseProcedureDeclaration( Scope *scope ) /* TODO: assign symbols to relative addresses (base pointer) */ /* TODO: initialize local variables */ - parseStatementBlock( symbol->scope ); + Expect( S_begin ); + parseStatementSequence( symbol->scope ); + if( symbol->is_func ) { + ExpressionNode *node = NULL; + Expect( S_return ); + node = parseExpression( symbol->scope ); + if( sym == S_semicolon ) { + sym = getSym( ); + } + (void)node; + /* TODO: add parsing return with local here, emit code + * for returning function value (what convention are + * we going to apply? stack? register? + */ + } + Expect( S_end ); + /* discard locals, restore base pointer, discard params */ if( size_locals > 0 ) { @@ -2387,7 +2459,7 @@ static void parseProcedureDeclaration( Scope *scope ) static void parseProcedureBlock( Scope *scope ) { - while( sym == S_procedure ) { + while( sym == S_procedure || sym == S_function ) { parseProcedureDeclaration( scope ); } } @@ -2423,7 +2495,9 @@ static void parseModule( Scope *scope ) parseDeclarationBlock( scope ); Emit( "%s:\n", entry_label ); - parseStatementBlock( scope ); + Expect( S_begin ); + parseStatementSequence( scope ); + Expect( S_end ); free( entry_label ); } diff --git a/ecomp-c/minie.ebnf b/ecomp-c/minie.ebnf index be68ba8..2bf9708 100644 --- a/ecomp-c/minie.ebnf +++ b/ecomp-c/minie.ebnf @@ -9,7 +9,7 @@ Character = "'" Digit | Letter | Special | "'" . String = """" { Character } """" . # parser -Factor = Number | Character | String | Identifier [ "[" Expression "]" ] | "(" Expression ")" | "not" Factor . +Factor = Number | Character | String | Identifier [ "[" Expression "]" | ParameterList ] | "(" Expression ")" | "not" Factor . Term = Factor { ( "*" | "/" | "mod" | "and" ) Factor } . SimpleExpression = Term { ( "+" | "-" | "or" ) Term } . RelationalOperator = "=" | "<>" | "<" | ">" | "<=" | ">=" . @@ -21,7 +21,6 @@ ParameterList = "(" Expression { "," Expression } ")" . ProcedureCall = Identifier [ ParameterList ] . Statement = Assignment | IfStatement | WhileStatement | ProcedureCall . StatementSequence = Statement { ";" Statement } . -StatementBlock = "begin" StatementSequence "end" . SimpleType = Identifier . ArrayType = "array" [ ConstExpression ] "of" Type . Type = SimpleType | ArrayType . @@ -31,9 +30,9 @@ ConstBlock = "const" { ConstDeclaration ";" } . VariableDeclaration = Identifier { "," Identifier } ":" Type [ ":=" ConstExpression ] . VariableBlock = "var" { VariableDeclaration ";" } . ParameterDeclaration = Identifier ":" Type . -ParamaterDeclarationList = "(" ParameterDeclaration { "," ParameterDeclaration } ")" . -ProcedureDeclaration = "procedure" Identifier [ ParamaterDeclarationList ] ";" ProcedureDeclarationBlock StatementBlock . +ParamaterDeclarationList = "(" ParameterDeclaration { "," ParameterDeclaration } ")" [ ":" Type ] . +ProcedureDeclaration = [ "procedure" | "function" ] Identifier [ ParamaterDeclarationList ] ";" ProcedureDeclarationBlock "begin" StatementSequence [ "return" Type ] "end" . ProcedureDeclarationBlock = [ ConstBlock ] [ VariableBlock ] . ProcedureBlock = { ProcedureDeclaration } . DeclarationBlock = [ ConstBlock ] [ VariableBlock ] [ ProcedureBlock ] . -Module = "module" Identifier ";" DeclarationBlock StatementBlock . +Module = "module" Identifier ";" DeclarationBlock "begin" StatementSequence "end" . diff --git a/ecomp-c/test1.e b/ecomp-c/test1.e index 80d9586..9300793 100644 --- a/ecomp-c/test1.e +++ b/ecomp-c/test1.e @@ -32,7 +32,7 @@ var s2 : array 10 of character := "hello"; a1 : array 10 of integer; -procedure B( n : integer, m : integer ); +procedure B( n : integer, m : integer, f : boolean ); procedure A; const @@ -44,16 +44,28 @@ var begin a1[5] := 43; s[0] := 'L'; - B( a1[5], 7 ); + B( a1[5], 7, true ); end -procedure B( n : integer, m : integer ); +procedure B( n : integer, m : integer, f : boolean ); var x : integer; begin - x := n - m; - a1[4] := x; + if f do + x := n - m; + a1[4] := x; + end +end + +function iszero( c : character ) : boolean; +var + res : boolean := false; +begin + if c = '0' do + res := true + end + return res; end begin @@ -98,5 +110,10 @@ begin a1[3] := 42; s2[a1[2]] := 'Z'; A; - B( 2, 1 ); + B( 2, 1, false ); + if iszero( '0' ) do + i := 1 + else + i := 2 + end end -- cgit v1.2.3-54-g00ecf