int col; int row; int pushback; int token; int DEBUG_SCANNER; enum { MAX_IDENT_LEN = 20 }; void pushBack( int c ) { pushback = c; } int getChar( ) { int c; if( pushback ) { c = pushback; pushback = 0; return c; } c = getchar( ); if( c == EOF ) { return c; } col++; if( c == '\n' ) { col = 0; row++; } return c; } int skipWhite( ) { int c; c = getChar( ); while( isspace( c ) ) { c = getChar( ); } return c; } enum { S_PLUS = 1, S_MINUS, S_STAR, S_SLASH, S_SEMICOLON, S_EQUALS, S_INT = 10, S_IDENT, S_NUM = 20, S_ERR = 30, S_EOI = 31 }; void printErrorHeader( ) { putstring( "Error line " ); putint( row ); putstring( ", pos " ); putint( col ); putstring( ": " ); } int num; void scanNumber( int c ) { num = c - '0'; c = getChar( ); while( isdigit( c ) ) { num = 10 * num + ( c - '0' ); c = getChar( ); } pushBack( c ); } /* c4: no data segment allocation in char array decleration */ char *ident; /*char ident[20]; char ident[MAX_IDENT_LEN]; */ void scanIdent( int c ) { int n; n = 0; while( isalnum( c ) || ( c == '_' ) ) { ident[n] = c; n++; if( n >= MAX_IDENT_LEN - 1 ) { printErrorHeader( ); putstring( "too long identifier" ); putnl( ); exit( EXIT_FAILURE ); } c = getChar( ); } ident[n] = 0; /* c4 doesn't handle '\0' */ pushBack( c ); } int keyword( char *ident ) { switch( ident[0] ) { case 'i': if( strcmp( ident, "int" ) == 0 ) { return S_INT; } else { return 0; } break; default: return 0; } } int getToken( ) { int t; int c; c = skipWhite( ); switch( c ) { case EOF: t = S_EOI; break; case '+': t = S_PLUS; break; case '-': t = S_MINUS; break; case '*': t = S_STAR; break; case '/': c = getChar( ); if( c == '/' ) { while( c != '\n' ) { c = getChar( ); } t = getToken( ); } else if( c == '*' ) { do { while( c != '*' ) { c = getChar( ); } c = getChar( ); } while( c != '/' ); c = getChar( ); t = getToken( ); } else { pushBack( c ); t = S_SLASH; } break; case ';': t = S_SEMICOLON; break; case '=': t = S_EQUALS; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': scanNumber( c ); t = S_NUM; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': scanIdent( c ); if( ( t = keyword( ident ) ) ) { } else { t = S_IDENT; } break; default: t = S_ERR; printErrorHeader( ); putstring( "unknown token '" ); putchar( c ); putstring( "'" ); putnl( ); exit( EXIT_FAILURE ); } if( DEBUG_SCANNER ) { putint( row ); putchar( '/' ); putint( col ); putstring( ": " ); putint( t ); if( t == S_NUM ) { putchar( '(' ); putint( num ); putchar( ')' ); } putnl( ); } return t; } void expect( int must, char *what ) { if( token == must ) { token = getToken( ); } else { printErrorHeader( ); putstring( what ); putstring( " expected" ); putnl( ); exit( EXIT_FAILURE ); } } void parseExpression( ) { if( token == S_EOI ) { printErrorHeader( ); putstring( "unexpected eof in expression" ); putnl( ); exit( EXIT_FAILURE ); } if( token == S_NUM ) { putstring( "immediate int " ); putint( num ); putnl( ); } token = getToken( ); if( token == S_PLUS ) { token = getToken( ); parseExpression( ); } else if( token == S_MINUS ) { token = getToken( ); parseExpression( ); } else if( token == S_STAR ) { token = getToken( ); parseExpression( ); } else if( token == S_SLASH ) { token = getToken( ); parseExpression( ); } else if( token == S_EOI || token == S_SEMICOLON ) { return; } else { printErrorHeader( ); putstring( "unexpected token '" ); putint( token ); putstring( "' in expression" ); putnl( ); exit( EXIT_FAILURE ); } } struct Symbol { char *name; struct Symbol *next; }; struct Symbol *symbol; struct Symbol *createSymbol( char *s ) { struct Symbol *sym; sym = (struct Symbol *)malloc( sizeof ( struct Symbol ) ); sym->name = (char *)strdup( s ); sym->next = NULL; return sym; } void freeSymbol( struct Symbol *sym ) { free( sym->name ); free( (char *)sym ); } void parseDeclaration( ) { struct Symbol *sym; expect( S_INT, "int" ); expect( S_IDENT, "identifier" ); putstring( "Adding glob: " ); putstring( ident ); putnl( ); sym = createSymbol( ident ); freeSymbol( sym ); expect( S_SEMICOLON, ";" ); } void parseAssignment( ) { token = getToken( ); expect( S_EQUALS, "=" ); parseExpression( ); expect( S_SEMICOLON, ";" ); } void parseStatement( ) { if( token == S_INT ) { parseDeclaration( ); } else if( token == S_IDENT ) { parseAssignment( ); } else if( token == S_EOI ) { return; } } int main( int argc, char **argv ) { col = 0; row = 1; pushback = 0; DEBUG_SCANNER = 1; symbol = NULL; ident = (char *)malloc( MAX_IDENT_LEN+1 ); token = getToken( ); while( token != S_EOI ) { parseStatement( ); } free( (char *)ident ); exit( EXIT_SUCCESS ); return EXIT_SUCCESS; }