From a75c766f80126525e8dfa525b32252ba38b17b26 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 30 Oct 2021 20:54:23 +0200 Subject: cc: some proper checking of return types and some primitive check for missing or superflous return statements --- miniany/README.html | 8 ++++++++ miniany/cc.c | 35 +++++++++++++++++++++++++++++++++++ miniany/cc.wg | 14 ++++++++++---- miniany/test1.c | 1 - 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/miniany/README.html b/miniany/README.html index ca5cdf7..c40d9f8 100644 --- a/miniany/README.html +++ b/miniany/README.html @@ -263,6 +263,14 @@ cat c4.c4 EOF c4.c EOF cc.c EOF hello.c | ./c4 +

Return statement

+

Implemention status: yes, but..

+

Reasoning:

+

Register Allocation

Implementation status: yes

Reasoning:

diff --git a/miniany/cc.c b/miniany/cc.c index 44cdd76..22781a2 100644 --- a/miniany/cc.c +++ b/miniany/cc.c @@ -365,6 +365,7 @@ struct Symbol { 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 */ + int seen_return; /* whether we saw a return in the definiton of a function (SYMBOL_CLASS_FUNCTION) */ }; struct Symbol *createSymbol( int class, char *s ) @@ -526,6 +527,7 @@ struct Parser { int token; struct Scanner *scanner; struct Scope *global_scope; + struct Symbol *current_function; int debug; }; @@ -1099,6 +1101,7 @@ struct Parser *createParser( ) parser->scanner = createScanner( ); parser->global_scope = createScope( "global" ); parser->debug = 0; + parser->current_function = NULL; return parser; } @@ -1561,11 +1564,30 @@ void parseDo( struct Compiler *compiler ) void parseReturn( struct Compiler *compiler ) { struct Parser *parser; + struct Symbol *sym; struct ASTnode *node; parser = compiler->parser; + sym = parser->current_function; + if( sym == NULL ) { + scannerPrintErrorHeader( parser->scanner ); + putstring( "return outside a function" ); + putnl( ); + exit( EXIT_FAILURE ); + } + if( sym->return_type == S_VOID ) { + scannerPrintErrorHeader( parser->scanner ); + putstring( "return inside function '" ) ; + putstring( sym->name ); + putstring( "' can not return any value" ); + putnl( ); + exit( EXIT_FAILURE ); + } + sym->seen_return = 1; + parserExpect( parser, S_RETURN, "return" ); node = parseExpression( parser, 0 ); + /* TODO: verify that sym->return_type fits to the type of the expression */ generateFromAST( compiler->generator, node, NOREG ); freeASTnode( node ); parserExpect( parser, S_SEMICOLON, ";" ); @@ -1632,6 +1654,8 @@ void parseFunctionDeclaration( struct Compiler *compiler ) sym = createSymbol( SYMBOL_CLASS_FUNCTION, parser->scanner->ident ); insertSymbol( parser->global_scope, sym ); sym->return_type = type; + sym->seen_return = 0; + parser->current_function = sym; } else { scannerPrintErrorHeader( parser->scanner ); putstring( "duplicate global symbol '" ); @@ -1653,7 +1677,18 @@ void parseFunctionDeclaration( struct Compiler *compiler ) parserExpect( parser, S_LPAREN, "(" ); /* TODO: parse parameter list */ parserExpect( parser, S_RPAREN, ")" ); + parseStatementBlock( compiler ); + + if( sym->return_type != S_VOID && !sym->seen_return ) { + scannerPrintErrorHeader( parser->scanner ); + putstring( "return excpected in non-void function '" ); + putstring( sym->name ); + putstring( "'" ); + putnl( ); + exit( EXIT_FAILURE ); + } + putstring( "pop ebp" ); putnl( ); putstring( "ret" ); putnl( ); genFreeAllRegs( compiler->generator ); diff --git a/miniany/cc.wg b/miniany/cc.wg index 352d664..09ac15d 100644 --- a/miniany/cc.wg +++ b/miniany/cc.wg @@ -30,13 +30,13 @@ WordGrinder dumpfile v3: this is a text file; diff me! .clipboard.viewmode: 1 .clipboard.wordcount: 6 .documents.1.co: 6 -.documents.1.cp: 38 -.documents.1.cw: 8 +.documents.1.cp: 191 +.documents.1.cw: 21 .documents.1.margin: 0 .documents.1.name: "main" .documents.1.sticky_selection: false .documents.1.viewmode: 1 -.documents.1.wordcount: 2863 +.documents.1.wordcount: 2988 .fileformat: 8 .findtext: "Note" .menu.accelerators.^@: "ZM" @@ -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: "/home/abaumann/projects/compilertests/miniany/cc.wg" +.name: "/media/sd/abaumann/projects/compilertests/miniany/cc.wg" .replacetext: "" .statusbar: true .current: 1 @@ -334,6 +334,12 @@ H3 Dangling else P Implementation status: no P Reasoning: LB Don't allow non-blocked if/else, just avoid then dangling else problem, it's uninteresting and in C not as bad as in PASCAL-like languages, as the block markers are just one character big. +H3 Return statement +P Implemention status: yes, but.. +P Reasoning: +LB There are good reasons not to allow return everywhere in the code, see newest Oberon revisions allowing RETURN only at the end of the function declaration. There are benefits like easier detection whether the function returns a function, easier flow analysis (image returns in complicated if-else-statements). For now we allow it everywhere, but we should try hard not to use it in the middle of code blocks. +LB There is an argument from the code correctness point of view as return in the middle of code makes the code hard to reason about (similar to too many if-else-statements) +LB Error handling is really hard, for now we check only whether we see a return at all anywhere in the body. H3 Register Allocation P Implementation status: yes P Reasoning: diff --git a/miniany/test1.c b/miniany/test1.c index 4c919ce..20986e3 100644 --- a/miniany/test1.c +++ b/miniany/test1.c @@ -1,6 +1,5 @@ /* test1 */ -/* TODO: check void (no return allowed) and check for int (in this case it is required) */ int f( ) { return 42; -- cgit v1.2.3-54-g00ecf