123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- /* This file contains the parser for the 'EM_table'.
- * Every row in the table is converted to a C-function.
- * The parser is a fairly simple program, for each row it prints a function-
- * header and the following actions are printed as C-statements. A CALL is just
- * copied, and an ASSEM_INSTR will be handed to the routine assemble().
- * Assemble() will turn the assembly-string into a sequence of C-function calls.
- * How this should be done is expressed in the 'as_table'.
- *
- * There are however some complicating factors:
- * - A row in the 'EM_table' may contain CONDITION's.
- * The parser supports this by outptutting some "if" and "else"'s.
- *
- * - The user is allowed to use some abbreviation in the 'EM_table', (s)he
- * can use the DEF_C_INSTR's ( e.g. C_loe..).
- * One such DEF_C_INSTR must be expanded in 3 or more C-functions.
- * The solution is to copy the DEF_C_INSTR to a temporary file. Then
- * this file will be processed as many times as needed to generate all
- * the C-functions.
- *
- * - The assembler-instructions must be processed in blocks not one at a
- * time, so buffering is needed.
- *
- * - When generating object-code, the user can make use of the dist()
- * function. This function should return the number of bytes between
- * the current instruction and a labelled one, both forward and backward
- * references must be handled.
- * This requires the saving of the generated function, and
- * backpatching in a second phase.
- */
- {
- #include <system.h>
- #include "decl.h"
- #include "em.h"
- extern char yytext[];
- extern int yylineno;
- extern int first_action, last_action, token;
- t_token tok, stok;
- int no_conversions = FALSE, library, segment = UNKNOWN;
- File *outfile;
- char *to_change;
- }
- %token C_INSTR, DEF_C_INSTR, CONDITION, ARROW,
- CALL, ASSEM_INSTR, DEFAULT, ERROR;
- %start table, table;
- %start def_row, def_row;
- %start c_table, c_table;
- %lexical lex_analyzer ;
- table : row*
- ;
- row : C_INSTR { set_outfile( yytext); header( yytext);
- set_segment(segment);
- }
- [ special | simple] { out( "}\n\n");}
- | DEF_C_INSTR { init_defaults( yytext);}
- [ Dspecial | Dsimple] { handle_defaults();}
- ;
- special :
- { out( "if( 0 ) ;\n"); }
- [ CONDITION { out( "else "); question( &yytext[0]);}
- simple { out( "}\n");}
- ]*
- DEFAULT { out( "else {\n");}
- simple { out( "}\n");}
- ;
- simple : ARROW { save_output();}
- actionlist { back_patch();}
- ;
- actionlist : { first_action = TRUE;}
- [ action { first_action = FALSE;}
- [ ';' action]*
- ]?
- '.'
- ;
- action : CALL { print_call( &yytext[0]);}
- | as_block { last_action = ( token == '.');
- do_block_assemble();}
- ;
- as_block : { init_as_block();}
- ASSEM_INSTR { save_as( &yytext[0]);}
- more_as
- ;
- more_as :
- %if ( next_token() == ASSEM_INSTR)
- ';'
- ASSEM_INSTR { save_as( &yytext[0]);}
- more_as
- |
- ;
- /* Grammar rules for a default-instruction, just copy to a temporary file. */
- Dspecial: CONDITION { out( " %s ", yytext);}
- Dsimple
- [ CONDITION { out( " %s ", yytext);}
- Dsimple
- ]*
- DEFAULT { out( " %s ", yytext);}
- Dsimple
- ;
- Dsimple : ARROW { out( "%s", yytext);}
- Dactionlist
- ;
- Dactionlist :
- [ Daction
- [ ';' { out( ";\n");}
- Daction
- ]*
- ]?
- '.' { out( ".\n");}
- ;
- Daction : CALL { out( "%s", yytext);}
- | ASSEM_INSTR { out( "\"%s\"", yytext);}
- ;
- def_row : { set_segment(segment);}
- [ special | simple] { out( "}\n\n");}
- ;
- /* This is a grammar to handle the -c flag ( only one entry has changed).
- * Skip all entries in the table until the one that has changed, then
- * use the grammar rules for the normal case above.
- */
- c_table : c_row*
- ;
- c_row : %if ( to_change && strcmp( yytext, to_change) == 0)
- C_INSTR { set_outfile( yytext); header( yytext);
- set_segment(segment);
- }
- [ special | simple] { out( "}\n\n"); to_change = 0; }
- | C_INSTR
- [ c_special | c_simple]
- | %if ( to_change && strcmp( yytext, to_change) == 0)
- DEF_C_INSTR { init_defaults( yytext);}
- [ Dspecial | Dsimple] { handle_defaults(); to_change = 0; }
- | DEF_C_INSTR
- [ c_special | c_simple]
- ;
- c_special : CONDITION
- c_simple
- [ CONDITION
- c_simple
- ]*
- DEFAULT
- c_simple
- ;
- c_simple: ARROW
- c_actionlist
- ;
- c_actionlist :
- [ c_action [ ';' c_action]* ]? '.'
- ;
- c_action: CALL
- | ASSEM_INSTR
- ;
- {
- int saved = 0, token;
- int nerrors = 0;
- LLmessage( inserted_token)
- int inserted_token;
- {
- nerrors++;
- if ( inserted_token == 0) {
- fprint( STDERR, "EM_table : syntax error in line %d, >>",
- yylineno);
- print_token( LLsymb);
- fprint( STDERR, "<< will be deleted!!\n");
- }
- else if ( inserted_token < 0) {
- fprint(STDERR,"EM_table : syntax error in line %d, garbage at end of table\n",
- yylineno);
- }
- else {
- fprint( STDERR, "EM_table : syntax error in line %d, >>",
- yylineno);
- print_token( inserted_token);
- fprint( STDERR, "<< will be inserted!!\n");
- token = LLsymb;
- saved = 1;
- }
- }
- print_token( token)
- int token;
- {
- switch ( token) {
- case C_INSTR : fprint( STDERR, "C_INSTR %s", yytext);
- break;
- case ASSEM_INSTR : fprint( STDERR, "STRING %s", yytext);
- break;
- case CALL : fprint( STDERR, "CALL %s", yytext);
- break;
- case ARROW : fprint( STDERR, "==> ");
- break;
- case CONDITION: fprint( STDERR, "CONDITION %s", yytext);
- break;
- case DEFAULT : fprint( STDERR, "default ");
- break;
- case ERROR : fprint( STDERR, "unmatched %s", yytext);
- break;
- default : fprint( STDERR, " %c", token);
- break;
- }
- }
- /* The lexical analyzer.
- * It uses mylex() to get the tokens.
- * It supports the buffering of one token.
- * If the curent token is a C_INSTR it will set the global variable
- * 'C_instr_info' to point to the correct information ( arguments, header,
- * etc.).
- */
- int lex_analyzer()
- {
- extern char *next;
- if ( saved) {
- saved = 0;
- }
- else {
- token = mylex();
- *next = '\0';
- }
- if ( token == C_INSTR)
- set_C_instr_info( yytext);
- return( token);
- }
- int next_token()
- {
- extern char *next;
- if ( !saved) {
- token = mylex();
- *next = '\0';
- saved = 1;
- }
- return( token);
- }
- /******************************************************************************/
- /* Handle arguments :
- * -l : Library, generate one function per file.
- * -c <name> : Change, only update the <name> file.
- */
- main( argc, argv)
- int argc;
- char **argv;
- {
- outfile = STDOUT;
- if ( argc > 1) {
- if ( strcmp( argv[1], "-l") == 0)
- library = TRUE;
- else if( strcmp( argv[1], "-c") == 0) {
- library = TRUE;
- to_change = argv[2];
- c_table();
- if (to_change) {
- fprint( STDERR, "No rule for %s\n", to_change);
- exit( 1);
- }
- exit(nerrors);
- }
- }
- else {
- library = FALSE;
- file_header();
- }
-
- table();
- exit(nerrors);
- }
- }
|