Pristine Ack-5.5
[Ack-5.5.git] / util / ceg / EM_parser / common / pars.g
1 /* This file contains the parser for the 'EM_table'.
2  * Every row in the table is converted to a C-function.
3  * The parser is a fairly simple program, for each row it prints a function-
4  * header and the following actions are printed as C-statements. A CALL is just
5  * copied, and an ASSEM_INSTR will be handed to the routine assemble().
6  * Assemble() will turn the assembly-string into a sequence of C-function calls.
7  * How this should be done is expressed in the 'as_table'.
8  *
9  * There are however some complicating factors:
10  *      - A row in the 'EM_table' may contain CONDITION's. 
11  *        The parser supports this by outptutting some "if" and "else"'s.
12  *
13  *      - The user is allowed to use some abbreviation in the 'EM_table', (s)he
14  *        can use the DEF_C_INSTR's ( e.g. C_loe..).
15  *        One such DEF_C_INSTR must be expanded in 3 or more C-functions.
16  *        The solution is to copy the DEF_C_INSTR to a temporary file. Then
17  *        this file will be processed as many times as needed to generate all
18  *        the C-functions.
19  *
20  *      - The assembler-instructions must be processed in blocks not one at a
21  *        time, so buffering is needed.
22  *
23  *      - When generating object-code, the user can make use of the dist()
24  *        function. This function should return the number of bytes between
25  *        the current instruction and a labelled one, both forward and backward
26  *        references must be handled.
27  *        This requires the saving of the generated function, and 
28  *        backpatching in a second phase.
29  */
30 {
31
32 #include <system.h>
33 #include "decl.h"
34 #include "em.h"
35
36 extern char yytext[];
37 extern int yylineno;
38 extern int first_action, last_action, token;
39
40 t_token tok, stok;
41 int no_conversions = FALSE, library, segment = UNKNOWN;
42 File *outfile;
43 char *to_change;
44
45 }
46
47 %token  C_INSTR, DEF_C_INSTR, CONDITION, ARROW,
48         CALL, ASSEM_INSTR, DEFAULT, ERROR;
49 %start  table, table;
50 %start  def_row, def_row;
51 %start  c_table, c_table;
52 %lexical        lex_analyzer ;
53
54
55 table   : row*
56         ;
57
58 row     : C_INSTR               { set_outfile( yytext); header( yytext);
59                                   set_segment(segment);
60                                 }
61           [ special | simple]   { out( "}\n\n");}
62
63         | DEF_C_INSTR           { init_defaults( yytext);}
64           [ Dspecial | Dsimple] { handle_defaults();}
65         ;
66
67 special : 
68                                 { out( "if( 0 ) ;\n"); }
69
70           [ CONDITION           { out( "else "); question( &yytext[0]);}
71             simple              { out( "}\n");}
72           ]*
73
74           DEFAULT               { out( "else {\n");}
75           simple                { out( "}\n");}
76         ;
77
78 simple  : ARROW                 { save_output();}
79           actionlist            { back_patch();}
80         ;
81
82
83 actionlist :                    { first_action = TRUE;}
84         [ action                { first_action = FALSE;}
85           [ ';' action]*
86         ]?
87         '.'
88         ;
89
90 action  : CALL                  { print_call( &yytext[0]);}
91
92         | as_block              { last_action = ( token == '.');
93                                   do_block_assemble();}
94
95         ;
96
97 as_block :                      { init_as_block();}
98         ASSEM_INSTR             { save_as( &yytext[0]);}
99         more_as
100         ;
101
102 more_as :
103           %if ( next_token() == ASSEM_INSTR)
104           ';' 
105           ASSEM_INSTR           { save_as( &yytext[0]);}
106           more_as
107         |
108         ;
109
110
111 /* Grammar rules for a default-instruction, just copy to a temporary file. */
112
113 Dspecial: CONDITION             { out( " %s ", yytext);}
114           Dsimple               
115
116           [ CONDITION           { out( " %s ", yytext);}
117             Dsimple             
118           ]*
119
120           DEFAULT               { out( " %s ", yytext);}
121           Dsimple               
122         ;
123
124 Dsimple : ARROW                 { out( "%s", yytext);}
125           Dactionlist
126
127         ;
128
129 Dactionlist : 
130           [ Daction
131             [ ';'               { out( ";\n");}
132               Daction
133             ]*
134           ]?
135           '.'                   { out( ".\n");}
136         ;
137
138 Daction : CALL                  { out( "%s", yytext);}
139
140         | ASSEM_INSTR           { out( "\"%s\"", yytext);}
141
142         ;
143
144 def_row :                       { set_segment(segment);}
145         [ special | simple]     { out( "}\n\n");}
146         ;
147
148
149
150 /* This is a grammar to handle the -c flag ( only one entry has changed).
151  * Skip all entries in the table until the one that has changed, then
152  * use the grammar rules for the normal case above.
153  */
154
155 c_table : c_row*
156         ;
157
158 c_row   : %if ( to_change && strcmp( yytext, to_change) == 0)
159           C_INSTR               { set_outfile( yytext); header( yytext);
160                                   set_segment(segment);
161                                 }
162           [ special | simple]   { out( "}\n\n"); to_change = 0; }
163
164         | C_INSTR
165           [ c_special | c_simple]
166
167         | %if ( to_change && strcmp( yytext, to_change) == 0)
168           DEF_C_INSTR           { init_defaults( yytext);}
169           [ Dspecial | Dsimple] { handle_defaults(); to_change = 0; }
170
171         | DEF_C_INSTR
172           [ c_special | c_simple]
173         ;
174
175 c_special : CONDITION
176           c_simple
177
178           [ CONDITION
179             c_simple
180           ]*
181
182           DEFAULT
183           c_simple
184         ;
185
186 c_simple: ARROW
187           c_actionlist
188
189         ;
190
191 c_actionlist : 
192           [ c_action [ ';' c_action]* ]? '.' 
193         ;
194
195 c_action: CALL
196         | ASSEM_INSTR
197         ;
198
199
200
201
202
203 {
204
205 int saved = 0, token;
206 int nerrors = 0;
207
208
209 LLmessage( inserted_token)
210 int inserted_token;
211 {
212         nerrors++;
213         if ( inserted_token == 0) {
214                 fprint( STDERR, "EM_table : syntax error in line %d, >>",
215                         yylineno);
216                 print_token( LLsymb);
217                 fprint( STDERR, "<<  will be deleted!!\n");
218         }
219         else if ( inserted_token < 0) {
220                 fprint(STDERR,"EM_table : syntax error in line %d, garbage at end of table\n",
221                          yylineno);
222         }
223         else {
224                 fprint( STDERR, "EM_table : syntax error in line %d, >>",
225                         yylineno);
226                 print_token( inserted_token);
227                 fprint( STDERR, "<<  will be inserted!!\n");
228                 token = LLsymb;
229                 saved = 1;
230         }
231 }
232
233 print_token( token)
234 int token;
235 {
236         switch ( token) {
237           case C_INSTR  : fprint( STDERR,  "C_INSTR  %s", yytext);
238                           break;
239           case ASSEM_INSTR : fprint( STDERR,  "STRING  %s", yytext);
240                           break;
241           case CALL     : fprint( STDERR,  "CALL  %s", yytext);
242                           break;
243           case ARROW    : fprint( STDERR,  "==> ");
244                           break;
245           case CONDITION: fprint( STDERR,  "CONDITION  %s", yytext);
246                           break;
247           case DEFAULT  : fprint( STDERR,  "default ");
248                           break;
249           case ERROR    : fprint( STDERR,  "unmatched  %s", yytext);
250                           break;
251           default       : fprint( STDERR, " %c", token);
252                           break;
253         }
254 }
255
256
257 /* The lexical analyzer.
258  *      It uses mylex() to get the tokens.
259  *      It supports the buffering of one token.
260  *      If the curent token is a C_INSTR it will set the global variable
261  *      'C_instr_info' to point to the correct information ( arguments, header,
262  *      etc.).
263  */
264
265 int lex_analyzer()
266 {
267         extern char *next;
268
269         if ( saved) {
270                 saved = 0;
271         }
272         else {
273                 token = mylex();
274                 *next = '\0';
275         }
276         if ( token == C_INSTR)
277                 set_C_instr_info( yytext);
278         return( token);
279 }
280
281 int next_token()
282 {
283         extern char *next;
284
285         if ( !saved) {
286                 token = mylex();
287                 *next = '\0';
288                 saved = 1;
289         }
290         return( token);
291 }
292
293
294 /******************************************************************************/
295
296 /* Handle arguments :
297  *      -l              : Library, generate one function per file.
298  *      -c <name>       : Change, only update the <name> file.
299  */
300
301 main( argc, argv)
302 int argc;
303 char **argv;
304 {
305         outfile = STDOUT;
306         if ( argc > 1) {
307                 if ( strcmp( argv[1], "-l") == 0)
308                         library = TRUE;
309                 else if( strcmp( argv[1], "-c") == 0) {
310                         library = TRUE;
311                         to_change = argv[2];
312                         c_table();
313                         if (to_change) {
314                                 fprint( STDERR, "No rule for %s\n", to_change);
315                                 exit( 1);
316                         }
317                         exit(nerrors);
318                 }
319         }
320         else {
321                 library = FALSE;
322                 file_header();
323         }
324         
325         table();
326         exit(nerrors);
327 }
328
329 }