summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2021-09-29 20:32:00 +0200
committerAndreas Baumann <mail@andreasbaumann.cc>2021-09-29 20:32:00 +0200
commit01ee6d3e1de75a1aa08afd06f4dafe49d099e77e (patch)
treee10eccb9076dfb5b4e7f4a94899496e916288625
parentc2bc809ca97bdebc8c70dd58a1c282c475a88557 (diff)
downloadcompilertests-01ee6d3e1de75a1aa08afd06f4dafe49d099e77e.tar.gz
compilertests-01ee6d3e1de75a1aa08afd06f4dafe49d099e77e.tar.bz2
cc: work on a working if
-rw-r--r--miniany/REQUIREMENTS13
-rwxr-xr-xminiany/build.sh2
-rw-r--r--miniany/cc.c116
-rw-r--r--miniany/libc-freestanding.c45
-rw-r--r--miniany/libc-hosted.c45
-rw-r--r--miniany/test1.c39
6 files changed, 235 insertions, 25 deletions
diff --git a/miniany/REQUIREMENTS b/miniany/REQUIREMENTS
index dd10d7e..cbee3f2 100644
--- a/miniany/REQUIREMENTS
+++ b/miniany/REQUIREMENTS
@@ -38,7 +38,7 @@ not implementing:
- ASTs are basically only useful when you start to optimize,
till then you can use an intermediate format (as C4) does
and a stack machine. They also make the code easier readable.
- For use they fore the introduction of pointers, references and structs.
+ For use they force the introduction of pointers, references and structs.
In expression parsing we see, that const folding already needs
an AST, because we should not emit code when still reading
a constant expression. It also seperates syntactical stuff like '['
@@ -117,5 +117,14 @@ TODO:
Inline assembly in the generated code duplicates code with the putint in libc-freestanding.
- error output is not on stderr, well, are we going to add stdout, stderr now
or do we write errors as sort of assembly comments?
-
+- AST debate:
+ - expressions really require an AST (just the A_ASSIGN itself with its reversed
+ order). IF, WHILE, etc. not, they can be in an AST or be endcoded directly (or if
+ not, what kind of optimizations do we loose?)
+ - the context of a boolean expression can be an if (in this case we would generate
+ direcly the jnXX instruction) and the far less often seen case of assigning it to
+ a variable. Knowing the contest would require an AST.
+ - AST should not be the output of whole programs, scoping is maybe better
+- don't allow non-blocked if/else, just avoid dangling else problems
+
diff --git a/miniany/build.sh b/miniany/build.sh
index b0c13f3..5891613 100755
--- a/miniany/build.sh
+++ b/miniany/build.sh
@@ -79,7 +79,7 @@ case "${COMPILER}:${MODE}" in
CFLAGS+=" -Wl,-emain"
;;
*:hosted)
- #~ CFLAGS+=" -lbsd"
+ CFLAGS+=" -lbsd"
;;
esac
diff --git a/miniany/cc.c b/miniany/cc.c
index 01472c9..c814f3d 100644
--- a/miniany/cc.c
+++ b/miniany/cc.c
@@ -15,6 +15,8 @@ enum {
S_SEMICOLON,
S_LPAREN,
S_RPAREN,
+ S_LBRACE,
+ S_RBRACE,
S_ASSIGN,
S_EQUALS,
S_NOT_EQUALS,
@@ -22,10 +24,12 @@ enum {
S_LESS_OR_EQUALS,
S_MORE,
S_MORE_OR_EQUALS,
- S_INT = 10,
+ S_INT = 50,
+ S_IF,
+ S_ELSE,
S_PUTINT,
- S_IDENT = 20,
- S_NUM = 30,
+ S_IDENT = 60,
+ S_NUM = 70,
S_EOI = 98,
S_ERR = 99
};
@@ -157,8 +161,18 @@ void scanIdent( struct Scanner *scanner )
int keyword( char *ident )
{
switch( ident[0] ) {
+ case 'e':
+ if( strcmp( ident, "else" ) == 0 ) {
+ return S_ELSE;
+ } else {
+ return 0;
+ }
+ break;
+
case 'i':
- if( strcmp( ident, "int" ) == 0 ) {
+ if( strcmp( ident, "if" ) == 0 ) {
+ return S_IF;
+ } else if( strcmp( ident, "int" ) == 0 ) {
return S_INT;
} else {
return 0;
@@ -260,6 +274,12 @@ int getToken( struct Scanner *scanner )
case ')':
scanner->token = S_RPAREN;
break;
+ case '{':
+ scanner->token = S_LBRACE;
+ break;
+ case '}':
+ scanner->token = S_RBRACE;
+ break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
scanNumber( scanner );
@@ -330,6 +350,7 @@ void freeSymbol( struct Symbol *sym )
struct Scope {
char *name;
struct Symbol *sym;
+ int labelNo;
};
struct Scope *createScope( char *name )
@@ -339,6 +360,7 @@ struct Scope *createScope( char *name )
scope = (struct Scope *)malloc( sizeof( struct Scope ) );
scope->name = strdup( name );
scope->sym = NULL;
+ scope->labelNo = 0;
return scope;
}
@@ -1132,7 +1154,7 @@ struct ASTnode *parseExpression( struct Parser *parser, int level )
parser->token = getToken( parser->scanner );
right = parseExpression( parser, parserOperatorPrecedence( parser, op ) );
left = createASTbinary( op, left, right );
- if( parser->token == S_EOI || parser->token == S_SEMICOLON ) {
+ if( parser->token == S_EOI || parser->token == S_SEMICOLON || parser->token == S_RPAREN ) {
return left;
}
op = parserTokenToOperator( parser, parser->token );
@@ -1209,6 +1231,70 @@ void parsePutint( struct Compiler *compiler )
freeASTnode( node );
}
+/* TODO c4: forward reference of function */
+void parseStatementBlock( struct Compiler *compiler );
+
+char *genGetLabel( struct Compiler *compiler, struct Scope *scope )
+{
+ char *label;
+ char *s;
+
+ label = (char *)malloc( MAX_IDENT_LEN );
+ strlcpy( label, "__", MAX_IDENT_LEN );
+ strlcat( label, scope->name, MAX_IDENT_LEN );
+ strlcat( label, "_", 1 );
+ s = (char *)malloc( MAX_IDENT_LEN );
+ itoa( scope->labelNo, s, 10 );
+ strlcat( label, s, MAX_IDENT_LEN );
+ free( (char *)s );
+ scope->labelNo++;
+
+ return label;
+}
+
+void parseIf( struct Compiler *compiler )
+{
+ struct Parser *parser;
+ struct ASTnode *node;
+ char *label1, *label2;
+
+ parser = compiler->parser;
+ parserExpect( parser, S_IF, "if" );
+ parserExpect( parser, S_LPAREN, "(" );
+ node = parseExpression( parser, 0 );
+ if( compiler->generator->debug ) {
+ putstring( "; if <cond> then" ); putnl( );
+ }
+ generateFromAST( compiler->generator, node, NOREG );
+ /* TODO: this should be condensed and optimized for the normal path
+ * (rare ifs, invert the condition, jmpXX directly */
+ putstring( "cmp al, 0" ); putnl( );
+ label1 = genGetLabel( compiler, compiler->parser->global_scope );
+ putstring( "je " ); putstring( label1 ); putnl( );
+ genFreeAllRegs( compiler->generator );
+ parserExpect( parser, S_RPAREN, ")" );
+ parseStatementBlock( compiler );
+ if( parser->token == S_ELSE ) {
+ label2 = genGetLabel( compiler, compiler->parser->global_scope );
+ putstring( "jmp " ); putstring( label2 ); putnl( );
+ if( compiler->generator->debug ) {
+ putstring( "; else" ); putnl( );
+ }
+ putstring( label1 ); putchar( ':' ); putnl( );
+ compiler->parser->token = getToken( compiler->parser->scanner );
+ parseStatementBlock( compiler );
+ putstring( label2 ); putchar( ':' ); putnl( );
+ free( label2 );
+ } else {
+ putstring( label1 ); putchar( ':' ); putnl( );
+ }
+
+ if( compiler->generator->debug ) {
+ putstring( "; fi" ); putnl( );
+ }
+ free( label1 );
+}
+
void parseStatement( struct Compiler *compiler )
{
struct Parser *parser;
@@ -1220,7 +1306,9 @@ void parseStatement( struct Compiler *compiler )
parseAssignment( compiler );
} else if( parser->token == S_PUTINT ) {
parsePutint( compiler );
- } else if( parser->token == S_EOI ) {
+ } else if( parser->token == S_IF ) {
+ parseIf( compiler );
+ } else if( parser->token == S_RBRACE || parser->token == S_EOI ) {
return;
} else {
scannerPrintErrorHeader( parser->scanner );
@@ -1232,6 +1320,18 @@ void parseStatement( struct Compiler *compiler )
}
}
+void parseStatementBlock( struct Compiler *compiler )
+{
+ struct Parser *parser;
+
+ parser = compiler->parser;
+ parserExpect( parser, S_LBRACE, "{" );
+ while( parser->token != S_RBRACE && parser->token != S_EOI ) {
+ parseStatement( compiler );
+ }
+ parserExpect( parser, S_RBRACE, "}" );
+}
+
/* compiler */
struct Compiler *createCompiler( )
@@ -1263,9 +1363,7 @@ int main( int argc, char **argv )
/* compiler->generator->debug = 1; */
genPrologue( compiler );
compiler->parser->token = getToken( compiler->parser->scanner );
- while( compiler->parser->token != S_EOI ) {
- parseStatement( compiler );
- }
+ parseStatementBlock( compiler );
genEpilogue( compiler );
freeCompiler( compiler );
diff --git a/miniany/libc-freestanding.c b/miniany/libc-freestanding.c
index a68a0c5..67f10fb 100644
--- a/miniany/libc-freestanding.c
+++ b/miniany/libc-freestanding.c
@@ -30,6 +30,51 @@ int strcmp( char *s1, char *s2 )
return *s1 - *s2;
}
+int strlcpy( char *d, const char *s, int n )
+{
+ int len = 0;
+
+ while( len < n && s[len] != '\0' ) {
+ d[len] = s[len];
+ len++;
+ }
+ d[len] = '\0';
+
+ while( s[len] != '\0' ) {
+ len++;
+ }
+
+ if( len >= n ) {
+ d[n-1] = '\0';
+ }
+
+ return len;
+}
+
+int strlcat( char *d, char *s, int n )
+{
+ int len = 0;
+ char *ss = s;
+ char *dd = d;
+
+ while( len < n && *dd != '\0' ) {
+ len++;
+ dd++;
+ }
+
+ if( len == n ) {
+ return len + strlen( s );
+ }
+
+ while( len + 1 < n && ( *dd++ = *ss++ ) ) {
+ len++;
+ }
+
+ *dd = '\0';
+
+ return len;
+}
+
int memcmp( char *s1, char *s2, int n )
{
while( n > 0 ) {
diff --git a/miniany/libc-hosted.c b/miniany/libc-hosted.c
index c6c1e69..e599b1d 100644
--- a/miniany/libc-hosted.c
+++ b/miniany/libc-hosted.c
@@ -4,6 +4,7 @@
*/
#define _XOPEN_SOURCE 600
+#include <bsd/string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
@@ -27,3 +28,47 @@ int putnl( void )
{
return puts( "" );
}
+
+/* TODO: duplicate of functions in libc-freestanding.c */
+
+static void strreverse( char *s )
+{
+ char *end = s + strlen( s ) - 1;
+
+ while( s < end ) {
+ *s ^= *end;
+ *end ^= *s;
+ *s ^= *end;
+ s++;
+ end--;
+ }
+}
+
+char *itoa( int v, char *s, int base )
+{
+ static char digit[] = "0123456789ABCDEF";
+ int sign = 0;
+ char *p = s;
+
+ if( base < 2 || base > 16 ) {
+ return NULL;
+ }
+
+ if( v < 0 ) {
+ v = -v;
+ sign = 1;
+ }
+
+ do {
+ *p++ = digit[v % base];
+ } while( ( v /= base ) > 0 );
+
+ if( sign ) {
+ *p++ = '-';
+ }
+ *p = '\0';
+
+ strreverse( s );
+
+ return s;
+}
diff --git a/miniany/test1.c b/miniany/test1.c
index 63f0b49..5747ca1 100644
--- a/miniany/test1.c
+++ b/miniany/test1.c
@@ -1,16 +1,29 @@
/* test1 */
-int i;
-int j;
-int k;
+{
+ int i;
+ int j;
+ int k;
-i = 12+25/5-2*3; // 25/5 -> 5, 12+5 -> 17, 2*3 -> 6, 17-6 -> 11
-putint( i );
-j = i/3+3*4; // 11 / 3 -> 3, 3*4 -> 12, 3+12 -> 15
-putint( j );
-k = 7 == 7; putint( k );
-k = 8 != 7; putint( k );
-k = 8 <= 9; putint( k );
-k = 8 < 9; putint( k );
-k = 9 > 8; putint( k );
-k = 9 >= 8; putint( k );
+ i = 12+25/5-2*3; // 25/5 -> 5, 12+5 -> 17, 2*3 -> 6, 17-6 -> 11
+ putint( i );
+ j = i/3+3*4; // 11 / 3 -> 3, 3*4 -> 12, 3+12 -> 15
+ putint( j );
+ k = 7 == 7; putint( k );
+ k = 8 != 7; putint( k );
+ k = 8 <= 9; putint( k );
+ k = 8 < 9; putint( k );
+ k = 9 > 8; putint( k );
+ k = 9 >= 8; putint( k );
+ k = 8 >= 8; putint( k );
+ k = 8 <= 8; putint( k );
+ if( i == j ) {
+ putint( 2 );
+ } else {
+ if( i > j ) {
+ putint( 1 );
+ } else {
+ putint( 0 );
+ }
+ }
+}