From 62924274b391dbfd16f4349bd46a2136f2a78b0e Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Wed, 13 Oct 2021 20:32:29 +0200 Subject: cc: some support for putchar and char store/load --- miniany/README.html | 4 ++-- miniany/cc.c | 62 +++++++++++++++++++++++++++++++++++++++++++++-------- miniany/cc.wg | 12 +++++------ miniany/test1.c | 4 +++- 4 files changed, 64 insertions(+), 18 deletions(-) diff --git a/miniany/README.html b/miniany/README.html index 7be5708..ca5cdf7 100644 --- a/miniany/README.html +++ b/miniany/README.html @@ -12,7 +12,7 @@

Similarly we simplify the C language to not use certain features which can cause trouble when bootstrapping:

Local version of C4

@@ -34,7 +34,7 @@
  • de-POSIX-ified, no open/read/close, use getchar from stdin only (don't assume the existence of a file system), this also means we had to create sort of an old style tape-file with FS markers to separate the files piped to c4.
  • The reason for all those adaptions is to minimize the dependency on the host system and to be able to use libc-freestanding.c.

    -

    Note: only too late I discovered that there was a C5 version of the same compiler, which would maybe have served better as a basis.

    +

    Note: Only too late I discovered that there was a C5 version of the same compiler, which would maybe have served better as a basis.

    Examples

    Running on the host system using the hosts C compiler

    Compiled in either hosted (host libc) or freestanding (our own libc, currently IA-32 Linux kernel only syscalls):

    diff --git a/miniany/cc.c b/miniany/cc.c index e977bc9..c72d290 100644 --- a/miniany/cc.c +++ b/miniany/cc.c @@ -32,6 +32,7 @@ enum { S_WHILE, S_DO, S_PUTINT, + S_PUTCHAR, S_IDENT = 60, S_NUM = 70, S_EOI = 98, @@ -194,6 +195,8 @@ int keyword( char *ident ) case 'p': if( strcmp( ident, "putint" ) == 0 ) { return S_PUTINT; + } else if( strcmp( ident, "putchar" ) == 0 ) { + return S_PUTCHAR; } break; @@ -599,7 +602,7 @@ void putlow8reg( struct Generator *generator, int reg ) break; default: scannerPrintErrorHeader( generator->scanner ); - putstring( "error using low 8-bit subreguster of reguster '" ); + putstring( "error using low 8-bit subreguster of register '" ); putstring( generator->regName[reg] ); putstring( "'" ); putnl( ); @@ -739,27 +742,41 @@ int genLoadImm( struct Generator *generator, int intval ) return reg; } -int genLoadIdent( struct Generator *generator, char *ident ) +int genLoadIdent( struct Generator *generator, struct Symbol *sym ) { int reg; reg = genAllocReg( generator ); putstring( "mov " ); - putreg( generator, reg ); + switch( sym->type ) { + case S_INT: + putreg( generator, reg ); + break; + case S_CHAR: + putlow8reg( generator, reg ); + break; + } putstring( ", [" ); - putstring( ident ); + putstring( sym->name ); putstring( "]" ); putnl( ); return reg; } -int genStoreIdent( struct Generator *generator, int reg, char *ident ) +int genStoreIdent( struct Generator *generator, int reg, struct Symbol *sym ) { putstring( "mov [" ); - putstring( ident ); + putstring( sym->name ); putstring( "], " ); - putreg( generator, reg ); + switch( sym->type ) { + case S_INT: + putreg( generator, reg ); + break; + case S_CHAR: + putlow8reg( generator, reg ); + break; + } putnl( ); return reg; @@ -921,10 +938,10 @@ int generateFromAST( struct Generator *generator, struct ASTnode *node, int inre reg = genLoadImm( generator, node->intval ); break; case A_IDENT: - reg = genLoadIdent( generator, node->sym->name ); + reg = genLoadIdent( generator, node->sym ); break; case A_LVIDENT: - reg = genStoreIdent( generator, inreg, node->sym->name ); + reg = genStoreIdent( generator, inreg, node->sym ); break; case A_ADD: reg = genAdd( generator, leftreg, rightreg ); @@ -979,6 +996,14 @@ void genPrologue( struct Compiler *compiler ) putstring( "use32" ); putnl( ); putstring( "org $1000000" ); putnl( ); putstring( "jmp _start" ); putnl( ); + putstring( "putchar:" ); putnl( ); + putstring( "mov [putint_string_fmt], eax" ); putnl( ); + putstring( "mov eax, 4" ); putnl( ); + putstring( "mov ebx, 1" ); putnl( ); + putstring( "mov ecx, putint_string_fmt" ); putnl( ); + putstring( "mov edx, 1" ); putnl( ); + putstring( "int 0x80" ); putnl( ); + putstring( "ret" ); putnl( ); putstring( "putint:" ); putnl( ); putstring( "mov esi, 0" ); putnl( ); putstring( "lea edi, [putint_string_fmt]" ); putnl( ); @@ -1301,6 +1326,23 @@ void parsePutint( struct Compiler *compiler ) freeASTnode( node ); } +void parsePutchar( struct Compiler *compiler ) +{ + struct Parser *parser; + struct ASTnode *node; + + parser = compiler->parser; + parserExpect( parser, S_PUTCHAR, "putchar" ); + parserExpect( parser, S_LPAREN, "(" ); + node = parseExpression( parser, 0 ); + parserExpect( parser, S_RPAREN, ")" ); + parserExpect( parser, S_SEMICOLON, ";" ); + generateFromAST( compiler->generator, node, NOREG ); + putstring( "call putchar" ); putnl( ); + genFreeAllRegs( compiler->generator ); + freeASTnode( node ); +} + /* TODO c4: forward reference of function */ void parseStatementBlock( struct Compiler *compiler ); @@ -1437,6 +1479,8 @@ void parseStatement( struct Compiler *compiler ) parseAssignment( compiler ); } else if( parser->token == S_PUTINT ) { parsePutint( compiler ); + } else if( parser->token == S_PUTCHAR ) { + parsePutchar( compiler ); } else if( parser->token == S_IF ) { parseIf( compiler ); } else if( parser->token == S_WHILE ) { diff --git a/miniany/cc.wg b/miniany/cc.wg index f09157a..2a0ad6d 100644 --- a/miniany/cc.wg +++ b/miniany/cc.wg @@ -29,16 +29,16 @@ WordGrinder dumpfile v3: this is a text file; diff me! .clipboard.margin: 0 .clipboard.viewmode: 1 .clipboard.wordcount: 6 -.documents.1.co: 9 -.documents.1.cp: 205 -.documents.1.cw: 21 +.documents.1.co: 7 +.documents.1.cp: 31 +.documents.1.cw: 25 .documents.1.margin: 0 .documents.1.name: "main" .documents.1.sticky_selection: false .documents.1.viewmode: 1 .documents.1.wordcount: 2863 .fileformat: 8 -.findtext: "Typedefs" +.findtext: "Note" .menu.accelerators.^@: "ZM" .menu.accelerators.^B: "SB" .menu.accelerators.BACKSPACE: "ZDPC" @@ -160,7 +160,7 @@ LB exit: terminate the process, return does not always work in all combination LB read/write: read from stdin linearly, write to stdout linearly, this is essentially a model using an input and an output tape. Those two functions must really exist. This basically eliminates the need for a file system which we might not have during early bootstrapping. P Similarly we simplify the C language to not use certain features which can cause trouble when bootstrapping: LB variable arguments: though simple in principle (just some pointers into the stack if you use a stack for function parameters), it is not typesafe. And the only example in practice it's really heavily used for is in printf-like functions. -LB preprocessor: it needs a filesystem, we take this outside of the compiler by feeding it an (eventually) concatenated list of *.c files. Note: in the hosted environemt we (and glibc) can use as many preprocessor features as they want, they just don't have to get visible in our code. +LB preprocessor: it needs a filesystem, we take this outside of the compiler by feeding it an (eventually) concatenated list of *.c files. Note: in the hosted environment we (and glibc) can use as many preprocessor features as they want, they just don't have to get visible in our code. LB two types: int and char, so we can interpret memory as words or as bytes. H2 Local version of C4 P The local version of C4 has the following adaoptions and extensions: @@ -179,7 +179,7 @@ LB converted printf to putstring/putint/putnl and some helper functions for LB removed all memory leaks LB de-POSIX-ified, no open/read/close, use getchar from stdin only (don't assume the existence of a file system), this also means we had to create sort of an old style tape-file with FS markers to separate the files piped to c4. P The reason for all those adaptions is to minimize the dependency on the host system and to be able to use libc-freestanding.c. -H3 Note: only too late I discovered that there was a C5 version of the same compiler, which would maybe have served better as a basis. +P Note: Only too late I discovered that there was a C5 version of the same compiler, which would maybe have served better as a basis. H2 Examples H3 Running on the host system using the hosts C compiler P Compiled in either hosted (host libc) or freestanding (our own libc, currently IA-32 Linux kernel only syscalls): diff --git a/miniany/test1.c b/miniany/test1.c index 2358298..30650f0 100644 --- a/miniany/test1.c +++ b/miniany/test1.c @@ -39,5 +39,7 @@ void main( ) i = i+1; } while( i <= 5 ); - c = 42; + c = 41; + c = c + 1; + putchar( c ); } -- cgit v1.2.3-54-g00ecf