#include #include #include #define MAXLEN 80 typedef enum { undef, eof, error, identifier, literal, dot, eql, lparen, rparen, lbrak, rbrak, lbrace, rbrace, bar } Sym; typedef struct { Sym sym; char value[MAXLEN]; } Symbol; typedef struct { int line; int col; FILE *f; } Scanner; static int get_char( Scanner *scan ) { int c = getc( scan->f ); scan->col++; if( c == '\n' ) { scan->line++; scan->col = 1; } return c; } static void unget_char( Scanner *scan, int c ) { ungetc( c, scan->f ); scan->col--; } static Symbol skip_blanks( Scanner *scan ) { int c; Symbol s; while( ( c = get_char( scan ) ) != EOF && iscntrl( c ) || ( c == ' ' ) ); if( c == EOF ) { s.sym = eof; return s; } unget_char( scan, c ); s.sym = undef; return s; } static int is_letter( char c ) { return( ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) ); } static int is_digit( char c ) { return( c >= '0' && c <= '9' ); } static Symbol get_sym( Scanner *scan ) { int c; Symbol s; int i; s.sym = undef; s = skip_blanks( scan ); if( s.sym == eof ) return s; c = get_char( scan ); if( c == EOF ) { s.sym = EOF; return s; } unget_char( scan, c ); if( is_letter( c ) ) { i = 0; s.sym = identifier; while( ( c = get_char( scan ) ) != EOF && ( is_letter( c ) || c == '-' ) ) { s.value[i++] = c; } s.value[i] = '\0'; } else if( c == '\"' ) { int escaped = 0; i = 0; s.sym = literal; (void)get_char( scan ); /* skip first quote */ while( ( c = get_char( scan ) ) != EOF && c != '\"' || escaped ) { if( c == '\\' ) { escaped = 1; } else { s.value[i++] = c; escaped = 0; } } s.value[i] = '\0'; /* ensure we end in a quote */ if( c != '\"' ) { fprintf( stderr, "ERROR(%d:%d): Unbalanced quote after literal '%s'\n", scan->line, scan->col, s.value ); s.sym = error; return s; } } else if( c == '=' ) { c = get_char( scan ); s.sym = eql; } else if( c == '(' ) { c = get_char( scan ); s.sym = lparen; } else if( c == ')' ) { c = get_char( scan ); s.sym = rparen; } else if( c == '[' ) { c = get_char( scan ); s.sym = lbrak; } else if( c == ']' ) { c = get_char( scan ); s.sym = rbrak; } else if( c == '{' ) { c = get_char( scan ); s.sym = lbrace; } else if( c == '}' ) { c = get_char( scan ); s.sym = rbrace; } else if( c == '|' ) { c = get_char( scan ); s.sym = bar; } else if( c == '.' ) { c = get_char( scan ); s.sym = dot; } else { c = get_char( scan ); s.sym = error; } return s; } static Scanner init_scanner( FILE *f ) { Scanner s; s.line = 1; s.col = 1; s.f = f; return s; } static void Expression( Scanner *scan, Symbol *s ); static void Factor( Scanner *scan, Symbol *s ) { if( s->sym == identifier ) { printf( "ident: %s\n", s->value ); *s = get_sym( scan ); } else if( s->sym == literal ) { printf( "literal: %s\n", s->value ); *s = get_sym( scan ); } else if( s->sym == lparen ) { *s = get_sym( scan ); Expression( scan, s ); if( s->sym == rparen ) { *s = get_sym( scan ); } else { fprintf( stderr, "ERROR(%d:%d): Expected ')' after expression\n", scan->line, scan->col ); } } else if( s->sym == lbrak ) { *s = get_sym( scan ); Expression( scan, s ); if( s->sym == rbrak ) { *s = get_sym( scan ); } else { fprintf( stderr, "ERROR(%d:%d): Expected ']' after expression\n", scan->line, scan->col ); } } else if( s->sym == lbrace ) { *s = get_sym( scan ); Expression( scan, s ); if( s->sym == rbrace ) { *s = get_sym( scan ); } else { fprintf( stderr, "ERROR(%d:%d): Expected ']' after expression\n", scan->line, scan->col ); } } else { fprintf( stderr, "ERROR(%d:%d): Unexpected symbol '%d' in factor\n", scan->line, scan->col, s->sym ); } } static void Term( Scanner *scan, Symbol *s ) { Factor( scan, s ); while( s->sym != bar && s->sym != rparen && s->sym != rbrace && s->sym != rbrak && s->sym != dot ) { Factor( scan, s ); } } static void Expression( Scanner *scan, Symbol *s ) { Term( scan, s ); while( s->sym == bar ) { *s = get_sym( scan ); Term( scan, s ); } } static void Production( Scanner *scan, Symbol *s ) { assert( s->sym == identifier ); *s = get_sym( scan ); if( s->sym == eql ) { *s = get_sym( scan ); } else { fprintf( stderr, "ERROR(%d:%d): Excepted '=' after identifier\n", scan->line, scan->col ); } Expression( scan, s ); if( s->sym == dot ) { *s = get_sym( scan ); } else { fprintf( stderr, "ERROR(%d:%d): Expected '.' after expression\n", scan->line, scan->col ); } } static void Syntax( Scanner *scan, Symbol *s ) { while( s->sym == identifier ) { Production( scan, s ); } } static void Compile( Scanner *scan ) { Symbol s; do { s = get_sym( scan ); if( s.sym == eof ) continue; Syntax( scan, &s ); } while( s.sym != eof ); } int main( void ) { Scanner scan; scan = init_scanner( stdin ); Compile( &scan ); return 0; }