330 lines
6.7 KiB
Plaintext
330 lines
6.7 KiB
Plaintext
/* 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);
|
|
}
|
|
|
|
}
|