summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2021-10-30 20:54:23 +0200
committerAndreas Baumann <mail@andreasbaumann.cc>2021-10-30 20:54:23 +0200
commita75c766f80126525e8dfa525b32252ba38b17b26 (patch)
treee5fafd2060dfd7569ece353237dd65ef3f993b93
parentdf1a8de0d0667f39b51cffa812dca780cc48bc14 (diff)
downloadcompilertests-a75c766f80126525e8dfa525b32252ba38b17b26.tar.gz
compilertests-a75c766f80126525e8dfa525b32252ba38b17b26.tar.bz2
cc: some proper checking of return types and some primitive check for missing or superflous return statements
-rw-r--r--miniany/README.html8
-rw-r--r--miniany/cc.c35
-rw-r--r--miniany/cc.wg14
-rw-r--r--miniany/test1.c1
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
<ul>
<li>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.</li>
</ul>
+<h3>Return statement</h3>
+<p>Implemention status: yes, but..</p>
+<p>Reasoning:</p>
+<ul>
+<li>There are good reasons not to allow <i>return </i>everywhere in the code, see newest Oberon revisions allowing <i>RETURN </i>only at the end of the function declaration. There are benefits like easier detection whether the function returns a function, easier flow analysis (image <i>returns </i>in complicated <i>if-else</i>-statements). For now we allow it everywhere, but we should try hard not to use it in the middle of code blocks.</li>
+<li>There is an argument from the code correctness point of view as <i>return </i>in the middle of code makes the code hard to reason about (similar to too many if-else-statements)</li>
+<li>Error handling is really hard, for now we check only whether we see a <i>return </i>at all anywhere in the body.</li>
+</ul>
<h3>Register Allocation</h3>
<p>Implementation status: yes</p>
<p>Reasoning:</p>
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;