#include #include #include #include /// scanner // constants enum { MAX_IDENT_LEN = 10 }; // token types typedef enum { S_undef, S_token, S_number, S_identifier, S_false, S_true, S_eof } Sym; typedef struct { Sym sym; union { char s[MAX_IDENT_LEN]; int n; bool b; }; int tag; } Symbol; char *symbol_tostr( Symbol s, char *buf, size_t buflen ) { switch( s.sym ) { case S_undef: snprintf( buf, buflen, "UNDEF" ); break; case S_token: if( isprint( s.tag ) ) { snprintf( buf, buflen, "TOK(%c)", s.tag ); } else { snprintf( buf, buflen, "TOK(0x%dx)", s.tag ); } break; case S_number: snprintf( buf, buflen, "NUMBER(%d)", s.n ); break; case S_identifier: snprintf( buf, buflen, "IDENT(%s)", s.s ); break; case S_eof: snprintf( buf, buflen, "EOF" ); break; default: snprintf( buf, buflen, "ILLEGAL(%d)", s.sym ); } return buf; } typedef struct { int peek; int row; int col; FILE *f; Symbol s; } Scanner; void scanner_init( Scanner *s, FILE *f ) { s->peek = ' '; s->row = 1; s->col = 1; s->f = f; s->s.sym = S_undef; } void scanner_skip_whitespace( Scanner *s ) { for( ; ; s->peek = getc( s->f ) ) { s->col++; if( s->peek == ' ' || s->peek == '\t' ) { continue; } else if( s->peek == '\n' ) { s->row++; s->col = 1; } else if( s->peek == EOF ) { break; } else { break; } } } Symbol scanner_get_int( Scanner *s ) { Symbol sym; sym.sym = S_number; sym.n = 0; do { sym.n = sym.n * 10 + ( s->peek - '0' ); s->peek = getc( s->f ); } while( isdigit( s->peek ) && ( s->peek != EOF ) ); return sym; } Symbol scanner_scan( Scanner *s ) { Symbol sym; if( s->peek == EOF ) { sym.sym = S_eof; return sym; } scanner_skip_whitespace( s ); if( isdigit( s->peek ) ) { sym = scanner_get_int( s ); return sym; } sym.sym = S_token; sym.tag = s->peek; s->peek = ' '; return sym; } /// parser typedef struct { Scanner *s; } Parser; void parser_init( Parser *p, Scanner *s ) { p->s = s; } void parser_error( Parser *p, const char *s, Symbol sym ) { char errbuf[255]; fprintf( stderr, "\nERR: %s at symbol '%s' at line %d, column %d\n", s, symbol_tostr( sym, errbuf, 255 ), p->s->row, p->s->col ); exit( 1 ); } void parser_term( Parser *p ) { Symbol s = scanner_scan( p->s ); if( s.sym == S_number ) { printf( "%d ", s.n ); } else { parser_error( p, "expecting number", s ); } } void parser_rest( Parser *p ) { Symbol s = scanner_scan( p->s ); if( s.sym == S_token ) { switch( s.tag ) { case '+': parser_term( p ); putchar( '+' ); putchar( ' ' ); parser_rest( p ); break; case '-': parser_term( p ); putchar( '-' ); putchar( ' ' ); parser_rest( p ); break; default: parser_error( p, "expecting operator '+' or '-'", s ); } } else if( s.sym == S_eof ) { return; } else { parser_error( p, "expecting an operator '+' or '-'", s ); } } void parser_expr( Parser *p ) { parser_term( p ); parser_rest( p ); } void parser_parse( Parser *p ) { parser_expr( p ); } /// main int main( void ) { Scanner s; Parser p; scanner_init( &s, stdin ); parser_init( &p, &s ); parser_parse( &p ); puts( "" ); exit( 0 ); }