1 /*
2 * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 // ADLPARSE.CPP - Architecture Description Language Parser
26 // Authors: Chris Vick and Mike Paleczny
27 #include "adlc.hpp"
28
29 //----------------------------ADLParser----------------------------------------
30 // Create a new ADL parser
ADLParser(FileBuff & buffer,ArchDesc & archDesc)31 ADLParser::ADLParser(FileBuff& buffer, ArchDesc& archDesc)
32 : _buf(buffer), _AD(archDesc),
33 _globalNames(archDesc.globalNames()) {
34 _AD._syntax_errs = _AD._semantic_errs = 0; // No errors so far this file
35 _AD._warnings = 0; // No warnings either
36 _curline = _ptr = NULL; // No pointers into buffer yet
37
38 _preproc_depth = 0;
39 _preproc_not_taken = 0;
40
41 // Delimit command-line definitions from in-file definitions:
42 _AD._preproc_list.add_signal();
43 }
44
45 //------------------------------~ADLParser-------------------------------------
46 // Delete an ADL parser.
~ADLParser()47 ADLParser::~ADLParser() {
48 if (!_AD._quiet_mode)
49 fprintf(stderr,"---------------------------- Errors and Warnings ----------------------------\n");
50 #ifndef ASSERT
51 if (!_AD._quiet_mode) {
52 fprintf(stderr, "**************************************************************\n");
53 fprintf(stderr, "***** WARNING: ASSERT is undefined, assertions disabled. *****\n");
54 fprintf(stderr, "**************************************************************\n");
55 }
56 #endif
57 if( _AD._syntax_errs + _AD._semantic_errs + _AD._warnings == 0 ) {
58 if (!_AD._quiet_mode)
59 fprintf(stderr,"No errors or warnings to report from phase-1 parse.\n" );
60 }
61 else {
62 if( _AD._syntax_errs ) { // Any syntax errors?
63 fprintf(stderr,"%s: Found %d syntax error", _buf._fp->_name, _AD._syntax_errs);
64 if( _AD._syntax_errs > 1 ) fprintf(stderr,"s.\n\n");
65 else fprintf(stderr,".\n\n");
66 }
67 if( _AD._semantic_errs ) { // Any semantic errors?
68 fprintf(stderr,"%s: Found %d semantic error", _buf._fp->_name, _AD._semantic_errs);
69 if( _AD._semantic_errs > 1 ) fprintf(stderr,"s.\n\n");
70 else fprintf(stderr,".\n\n");
71 }
72 if( _AD._warnings ) { // Any warnings?
73 fprintf(stderr,"%s: Found %d warning", _buf._fp->_name, _AD._warnings);
74 if( _AD._warnings > 1 ) fprintf(stderr,"s.\n\n");
75 else fprintf(stderr,".\n\n");
76 }
77 }
78 if (!_AD._quiet_mode)
79 fprintf(stderr,"-----------------------------------------------------------------------------\n");
80 _AD._TotalLines += linenum()-1; // -1 for overshoot in "nextline" routine
81
82 // Write out information we have stored
83 // // UNIXism == fsync(stderr);
84 }
85
86 //------------------------------parse------------------------------------------
87 // Each top-level keyword should appear as the first non-whitespace on a line.
88 //
parse()89 void ADLParser::parse() {
90 char *ident;
91
92 // Iterate over the lines in the file buffer parsing Level 1 objects
93 for( next_line(); _curline != NULL; next_line()) {
94 _ptr = _curline; // Reset ptr to start of new line
95 skipws(); // Skip any leading whitespace
96 ident = get_ident(); // Get first token
97 if (ident == NULL) { // Empty line
98 continue; // Get the next line
99 }
100 if (!strcmp(ident, "instruct")) instr_parse();
101 else if (!strcmp(ident, "operand")) oper_parse();
102 else if (!strcmp(ident, "opclass")) opclass_parse();
103 else if (!strcmp(ident, "ins_attrib")) ins_attr_parse();
104 else if (!strcmp(ident, "op_attrib")) op_attr_parse();
105 else if (!strcmp(ident, "source")) source_parse();
106 else if (!strcmp(ident, "source_hpp")) source_hpp_parse();
107 else if (!strcmp(ident, "register")) reg_parse();
108 else if (!strcmp(ident, "frame")) frame_parse();
109 else if (!strcmp(ident, "encode")) encode_parse();
110 else if (!strcmp(ident, "pipeline")) pipe_parse();
111 else if (!strcmp(ident, "definitions")) definitions_parse();
112 else if (!strcmp(ident, "peephole")) peep_parse();
113 else if (!strcmp(ident, "#line")) preproc_line();
114 else if (!strcmp(ident, "#define")) preproc_define();
115 else if (!strcmp(ident, "#undef")) preproc_undef();
116 else {
117 parse_err(SYNERR, "expected one of - instruct, operand, ins_attrib, op_attrib, source, register, pipeline, encode\n Found %s",ident);
118 }
119 }
120 // Add reg_class spill_regs after parsing.
121 RegisterForm *regBlock = _AD.get_registers();
122 if (regBlock == NULL) {
123 parse_err(SEMERR, "Did not declare 'register' definitions");
124 }
125 regBlock->addSpillRegClass();
126
127 // Done with parsing, check consistency.
128
129 if (_preproc_depth != 0) {
130 parse_err(SYNERR, "End of file inside #ifdef");
131 }
132
133 // AttributeForms ins_cost and op_cost must be defined for default behaviour
134 if (_globalNames[AttributeForm::_ins_cost] == NULL) {
135 parse_err(SEMERR, "Did not declare 'ins_cost' attribute");
136 }
137 if (_globalNames[AttributeForm::_op_cost] == NULL) {
138 parse_err(SEMERR, "Did not declare 'op_cost' attribute");
139 }
140 }
141
142 // ******************** Private Level 1 Parse Functions ********************
143 //------------------------------instr_parse------------------------------------
144 // Parse the contents of an instruction definition, build the InstructForm to
145 // represent that instruction, and add it to the InstructForm list.
instr_parse(void)146 void ADLParser::instr_parse(void) {
147 char *ident;
148 InstructForm *instr;
149 MatchRule *rule;
150 int match_rules_cnt = 0;
151
152 // First get the name of the instruction
153 if( (ident = get_unique_ident(_globalNames,"instruction")) == NULL )
154 return;
155 instr = new InstructForm(ident); // Create new instruction form
156 instr->_linenum = linenum();
157 _globalNames.Insert(ident, instr); // Add name to the name table
158 // Debugging Stuff
159 if (_AD._adl_debug > 1)
160 fprintf(stderr,"Parsing Instruction Form %s\n", ident);
161
162 // Then get the operands
163 skipws();
164 if (_curchar != '(') {
165 parse_err(SYNERR, "missing '(' in instruct definition\n");
166 }
167 // Parse the operand list
168 else get_oplist(instr->_parameters, instr->_localNames);
169 skipws(); // Skip leading whitespace
170 // Check for block delimiter
171 if ( (_curchar != '%')
172 || ( next_char(), (_curchar != '{')) ) {
173 parse_err(SYNERR, "missing '%%{' in instruction definition\n");
174 return;
175 }
176 next_char(); // Maintain the invariant
177 do {
178 ident = get_ident(); // Grab next identifier
179 if (ident == NULL) {
180 parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);
181 continue;
182 }
183 if (!strcmp(ident, "predicate")) instr->_predicate = pred_parse();
184 else if (!strcmp(ident, "match")) {
185 // Allow one instruction have several match rules.
186 rule = instr->_matrule;
187 if (rule == NULL) {
188 // This is first match rule encountered
189 rule = match_parse(instr->_localNames);
190 if (rule) {
191 instr->_matrule = rule;
192 // Special case the treatment of Control instructions.
193 if( instr->is_ideal_control() ) {
194 // Control instructions return a special result, 'Universe'
195 rule->_result = "Universe";
196 }
197 // Check for commutative operations with tree operands.
198 matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt);
199 }
200 } else {
201 // Find the end of the match rule list
202 while (rule->_next != NULL)
203 rule = rule->_next;
204 // Add the new match rule to the list
205 rule->_next = match_parse(instr->_localNames);
206 if (rule->_next) {
207 rule = rule->_next;
208 if( instr->is_ideal_control() ) {
209 parse_err(SYNERR, "unique match rule expected for %s\n", rule->_name);
210 return;
211 }
212 assert(match_rules_cnt < 100," too many match rule clones");
213 char* buf = (char*) malloc(strlen(instr->_ident) + 4);
214 sprintf(buf, "%s_%d", instr->_ident, match_rules_cnt++);
215 rule->_result = buf;
216 // Check for commutative operations with tree operands.
217 matchrule_clone_and_swap(rule, instr->_ident, match_rules_cnt);
218 }
219 }
220 }
221 else if (!strcmp(ident, "encode")) {
222 parse_err(SYNERR, "Instructions specify ins_encode, not encode\n");
223 }
224 else if (!strcmp(ident, "ins_encode")) ins_encode_parse(*instr);
225 // Parse late expand keyword.
226 else if (!strcmp(ident, "postalloc_expand")) postalloc_expand_parse(*instr);
227 else if (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr);
228 else if (!strcmp(ident, "size")) instr->_size = size_parse(instr);
229 else if (!strcmp(ident, "effect")) effect_parse(instr);
230 else if (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr);
231 else if (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse();
232 else if (!strcmp(ident, "constraint")) {
233 parse_err(SYNERR, "Instructions do not specify a constraint\n");
234 }
235 else if (!strcmp(ident, "construct")) {
236 parse_err(SYNERR, "Instructions do not specify a construct\n");
237 }
238 else if (!strcmp(ident, "format")) instr->_format = format_parse();
239 else if (!strcmp(ident, "interface")) {
240 parse_err(SYNERR, "Instructions do not specify an interface\n");
241 }
242 else if (!strcmp(ident, "ins_pipe")) ins_pipe_parse(*instr);
243 else { // Done with staticly defined parts of instruction definition
244 // Check identifier to see if it is the name of an attribute
245 const Form *form = _globalNames[ident];
246 AttributeForm *attr = form ? form->is_attribute() : NULL;
247 if (attr && (attr->_atype == INS_ATTR)) {
248 // Insert the new attribute into the linked list.
249 Attribute *temp = attr_parse(ident);
250 temp->_next = instr->_attribs;
251 instr->_attribs = temp;
252 } else {
253 parse_err(SYNERR, "expected one of:\n predicate, match, encode, or the name of"
254 " an instruction attribute at %s\n", ident);
255 }
256 }
257 skipws();
258 } while(_curchar != '%');
259 next_char();
260 if (_curchar != '}') {
261 parse_err(SYNERR, "missing '%%}' in instruction definition\n");
262 return;
263 }
264 // Check for "Set" form of chain rule
265 adjust_set_rule(instr);
266 if (_AD._pipeline) {
267 // No pipe required for late expand.
268 if (instr->expands() || instr->postalloc_expands()) {
269 if (instr->_ins_pipe) {
270 parse_err(WARN, "ins_pipe and expand rule both specified for instruction \"%s\";"
271 " ins_pipe will be unused\n", instr->_ident);
272 }
273 } else {
274 if (!instr->_ins_pipe) {
275 parse_err(WARN, "No ins_pipe specified for instruction \"%s\"\n", instr->_ident);
276 }
277 }
278 }
279 // Add instruction to tail of instruction list
280 _AD.addForm(instr);
281
282 // Create instruction form for each additional match rule
283 rule = instr->_matrule;
284 if (rule != NULL) {
285 rule = rule->_next;
286 while (rule != NULL) {
287 ident = (char*)rule->_result;
288 InstructForm *clone = new InstructForm(ident, instr, rule); // Create new instruction form
289 _globalNames.Insert(ident, clone); // Add name to the name table
290 // Debugging Stuff
291 if (_AD._adl_debug > 1)
292 fprintf(stderr,"Parsing Instruction Form %s\n", ident);
293 // Check for "Set" form of chain rule
294 adjust_set_rule(clone);
295 // Add instruction to tail of instruction list
296 _AD.addForm(clone);
297 rule = rule->_next;
298 clone->_matrule->_next = NULL; // One match rule per clone
299 }
300 }
301 }
302
303 //------------------------------matchrule_clone_and_swap-----------------------
304 // Check for commutative operations with subtree operands,
305 // create clones and swap operands.
matchrule_clone_and_swap(MatchRule * rule,const char * instr_ident,int & match_rules_cnt)306 void ADLParser::matchrule_clone_and_swap(MatchRule* rule, const char* instr_ident, int& match_rules_cnt) {
307 // Check for commutative operations with tree operands.
308 int count = 0;
309 rule->count_commutative_op(count);
310 if (count > 0) {
311 // Clone match rule and swap commutative operation's operands.
312 rule->matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt);
313 }
314 }
315
316 //------------------------------adjust_set_rule--------------------------------
317 // Check for "Set" form of chain rule
adjust_set_rule(InstructForm * instr)318 void ADLParser::adjust_set_rule(InstructForm *instr) {
319 if (instr->_matrule == NULL || instr->_matrule->_rChild == NULL) return;
320 const char *rch = instr->_matrule->_rChild->_opType;
321 const Form *frm = _globalNames[rch];
322 if( (! strcmp(instr->_matrule->_opType,"Set")) &&
323 frm && frm->is_operand() && (! frm->ideal_only()) ) {
324 // Previous implementation, which missed leaP*, but worked for loadCon*
325 unsigned position = 0;
326 const char *result = NULL;
327 const char *name = NULL;
328 const char *optype = NULL;
329 MatchNode *right = instr->_matrule->_rChild;
330 if (right->base_operand(position, _globalNames, result, name, optype)) {
331 position = 1;
332 const char *result2 = NULL;
333 const char *name2 = NULL;
334 const char *optype2 = NULL;
335 // Can not have additional base operands in right side of match!
336 if ( ! right->base_operand( position, _globalNames, result2, name2, optype2) ) {
337 if (instr->_predicate != NULL)
338 parse_err(SYNERR, "ADLC does not support instruction chain rules with predicates");
339 // Chain from input _ideal_operand_type_,
340 // Needed for shared roots of match-trees
341 ChainList *lst = (ChainList *)_AD._chainRules[optype];
342 if (lst == NULL) {
343 lst = new ChainList();
344 _AD._chainRules.Insert(optype, lst);
345 }
346 if (!lst->search(instr->_matrule->_lChild->_opType)) {
347 const char *cost = instr->cost();
348 if (cost == NULL) {
349 cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;
350 }
351 // The ADLC does not support chaining from the ideal operand type
352 // of a predicated user-defined operand
353 if( frm->is_operand() == NULL || frm->is_operand()->_predicate == NULL ) {
354 lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident);
355 }
356 }
357 // Chain from input _user_defined_operand_type_,
358 lst = (ChainList *)_AD._chainRules[result];
359 if (lst == NULL) {
360 lst = new ChainList();
361 _AD._chainRules.Insert(result, lst);
362 }
363 if (!lst->search(instr->_matrule->_lChild->_opType)) {
364 const char *cost = instr->cost();
365 if (cost == NULL) {
366 cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;
367 }
368 // It is safe to chain from the top-level user-defined operand even
369 // if it has a predicate, since the predicate is checked before
370 // the user-defined type is available.
371 lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident);
372 }
373 } else {
374 // May have instruction chain rule if root of right-tree is an ideal
375 OperandForm *rightOp = _globalNames[right->_opType]->is_operand();
376 if( rightOp ) {
377 const Form *rightRoot = _globalNames[rightOp->_matrule->_opType];
378 if( rightRoot && rightRoot->ideal_only() ) {
379 const char *chain_op = NULL;
380 if( rightRoot->is_instruction() )
381 chain_op = rightOp->_ident;
382 if( chain_op ) {
383 // Look-up the operation in chain rule table
384 ChainList *lst = (ChainList *)_AD._chainRules[chain_op];
385 if (lst == NULL) {
386 lst = new ChainList();
387 _AD._chainRules.Insert(chain_op, lst);
388 }
389 // if (!lst->search(instr->_matrule->_lChild->_opType)) {
390 const char *cost = instr->cost();
391 if (cost == NULL) {
392 cost = ((AttributeForm*)_globalNames[AttributeForm::_ins_cost])->_attrdef;
393 }
394 // This chains from a top-level operand whose predicate, if any,
395 // has been checked.
396 lst->insert(instr->_matrule->_lChild->_opType,cost,instr->_ident);
397 // }
398 }
399 }
400 }
401 } // end chain rule from right-tree's ideal root
402 }
403 }
404 }
405
406
407 //------------------------------oper_parse-------------------------------------
oper_parse(void)408 void ADLParser::oper_parse(void) {
409 char *ident;
410 OperandForm *oper;
411 AttributeForm *attr;
412 MatchRule *rule;
413
414 // First get the name of the operand
415 skipws();
416 if( (ident = get_unique_ident(_globalNames,"operand")) == NULL )
417 return;
418 oper = new OperandForm(ident); // Create new operand form
419 oper->_linenum = linenum();
420 _globalNames.Insert(ident, oper); // Add name to the name table
421
422 // Debugging Stuff
423 if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Operand Form %s\n", ident);
424
425 // Get the component operands
426 skipws();
427 if (_curchar != '(') {
428 parse_err(SYNERR, "missing '(' in operand definition\n");
429 return;
430 }
431 else get_oplist(oper->_parameters, oper->_localNames); // Parse the component operand list
432 skipws();
433 // Check for block delimiter
434 if ((_curchar != '%') || (*(_ptr+1) != '{')) { // If not open block
435 parse_err(SYNERR, "missing '%%{' in operand definition\n");
436 return;
437 }
438 next_char(); next_char(); // Skip over "%{" symbol
439 do {
440 ident = get_ident(); // Grab next identifier
441 if (ident == NULL) {
442 parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);
443 continue;
444 }
445 if (!strcmp(ident, "predicate")) oper->_predicate = pred_parse();
446 else if (!strcmp(ident, "match")) {
447 // Find the end of the match rule list
448 rule = oper->_matrule;
449 if (rule) {
450 while (rule->_next) rule = rule->_next;
451 // Add the new match rule to the list
452 rule->_next = match_parse(oper->_localNames);
453 if (rule->_next) {
454 rule->_next->_result = oper->_ident;
455 }
456 }
457 else {
458 // This is first match rule encountered
459 oper->_matrule = match_parse(oper->_localNames);
460 if (oper->_matrule) {
461 oper->_matrule->_result = oper->_ident;
462 }
463 }
464 }
465 else if (!strcmp(ident, "encode")) oper->_interface = interface_parse();
466 else if (!strcmp(ident, "ins_encode")) {
467 parse_err(SYNERR, "Operands specify 'encode', not 'ins_encode'\n");
468 }
469 else if (!strcmp(ident, "opcode")) {
470 parse_err(SYNERR, "Operands do not specify an opcode\n");
471 }
472 else if (!strcmp(ident, "effect")) {
473 parse_err(SYNERR, "Operands do not specify an effect\n");
474 }
475 else if (!strcmp(ident, "expand")) {
476 parse_err(SYNERR, "Operands do not specify an expand\n");
477 }
478 else if (!strcmp(ident, "rewrite")) {
479 parse_err(SYNERR, "Operands do not specify a rewrite\n");
480 }
481 else if (!strcmp(ident, "constraint"))oper->_constraint= constraint_parse();
482 else if (!strcmp(ident, "construct")) oper->_construct = construct_parse();
483 else if (!strcmp(ident, "format")) oper->_format = format_parse();
484 else if (!strcmp(ident, "interface")) oper->_interface = interface_parse();
485 // Check identifier to see if it is the name of an attribute
486 else if (((attr = _globalNames[ident]->is_attribute()) != NULL) &&
487 (attr->_atype == OP_ATTR)) oper->_attribs = attr_parse(ident);
488 else {
489 parse_err(SYNERR, "expected one of - constraint, predicate, match, encode, format, construct, or the name of a defined operand attribute at %s\n", ident);
490 }
491 skipws();
492 } while(_curchar != '%');
493 next_char();
494 if (_curchar != '}') {
495 parse_err(SYNERR, "missing '%%}' in operand definition\n");
496 return;
497 }
498 // Add operand to tail of operand list
499 _AD.addForm(oper);
500 }
501
502 //------------------------------opclass_parse----------------------------------
503 // Operand Classes are a block with a comma delimited list of operand names
opclass_parse(void)504 void ADLParser::opclass_parse(void) {
505 char *ident;
506 OpClassForm *opc;
507 OperandForm *opForm;
508
509 // First get the name of the operand class
510 skipws();
511 if( (ident = get_unique_ident(_globalNames,"opclass")) == NULL )
512 return;
513 opc = new OpClassForm(ident); // Create new operand class form
514 _globalNames.Insert(ident, opc); // Add name to the name table
515
516 // Debugging Stuff
517 if (_AD._adl_debug > 1)
518 fprintf(stderr,"Parsing Operand Class Form %s\n", ident);
519
520 // Get the list of operands
521 skipws();
522 if (_curchar != '(') {
523 parse_err(SYNERR, "missing '(' in operand definition\n");
524 return;
525 }
526 do {
527 next_char(); // Skip past open paren or comma
528 ident = get_ident(); // Grab next identifier
529 if (ident == NULL) {
530 parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);
531 continue;
532 }
533 // Check identifier to see if it is the name of an operand
534 const Form *form = _globalNames[ident];
535 opForm = form ? form->is_operand() : NULL;
536 if ( opForm ) {
537 opc->_oplst.addName(ident); // Add operand to opclass list
538 opForm->_classes.addName(opc->_ident);// Add opclass to operand list
539 }
540 else {
541 parse_err(SYNERR, "expected name of a defined operand at %s\n", ident);
542 }
543 skipws(); // skip trailing whitespace
544 } while (_curchar == ','); // Check for the comma
545 // Check for closing ')'
546 if (_curchar != ')') {
547 parse_err(SYNERR, "missing ')' or ',' in opclass definition\n");
548 return;
549 }
550 next_char(); // Consume the ')'
551 skipws();
552 // Check for closing ';'
553 if (_curchar != ';') {
554 parse_err(SYNERR, "missing ';' in opclass definition\n");
555 return;
556 }
557 next_char(); // Consume the ';'
558 // Add operand to tail of operand list
559 _AD.addForm(opc);
560 }
561
562 //------------------------------ins_attr_parse---------------------------------
ins_attr_parse(void)563 void ADLParser::ins_attr_parse(void) {
564 char *ident;
565 char *aexpr;
566 AttributeForm *attrib;
567
568 // get name for the instruction attribute
569 skipws(); // Skip leading whitespace
570 if( (ident = get_unique_ident(_globalNames,"inst_attrib")) == NULL )
571 return;
572 // Debugging Stuff
573 if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Ins_Attribute Form %s\n", ident);
574
575 // Get default value of the instruction attribute
576 skipws(); // Skip whitespace
577 if ((aexpr = get_paren_expr("attribute default expression string")) == NULL) {
578 parse_err(SYNERR, "missing '(' in ins_attrib definition\n");
579 return;
580 }
581 // Debug Stuff
582 if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr);
583
584 // Check for terminator
585 if (_curchar != ';') {
586 parse_err(SYNERR, "missing ';' in ins_attrib definition\n");
587 return;
588 }
589 next_char(); // Advance past the ';'
590
591 // Construct the attribute, record global name, and store in ArchDesc
592 attrib = new AttributeForm(ident, INS_ATTR, aexpr);
593 _globalNames.Insert(ident, attrib); // Add name to the name table
594 _AD.addForm(attrib);
595 }
596
597 //------------------------------op_attr_parse----------------------------------
op_attr_parse(void)598 void ADLParser::op_attr_parse(void) {
599 char *ident;
600 char *aexpr;
601 AttributeForm *attrib;
602
603 // get name for the operand attribute
604 skipws(); // Skip leading whitespace
605 if( (ident = get_unique_ident(_globalNames,"op_attrib")) == NULL )
606 return;
607 // Debugging Stuff
608 if (_AD._adl_debug > 1) fprintf(stderr,"Parsing Op_Attribute Form %s\n", ident);
609
610 // Get default value of the instruction attribute
611 skipws(); // Skip whitespace
612 if ((aexpr = get_paren_expr("attribute default expression string")) == NULL) {
613 parse_err(SYNERR, "missing '(' in op_attrib definition\n");
614 return;
615 }
616 // Debug Stuff
617 if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr);
618
619 // Check for terminator
620 if (_curchar != ';') {
621 parse_err(SYNERR, "missing ';' in op_attrib definition\n");
622 return;
623 }
624 next_char(); // Advance past the ';'
625
626 // Construct the attribute, record global name, and store in ArchDesc
627 attrib = new AttributeForm(ident, OP_ATTR, aexpr);
628 _globalNames.Insert(ident, attrib);
629 _AD.addForm(attrib);
630 }
631
632 //------------------------------definitions_parse-----------------------------------
definitions_parse(void)633 void ADLParser::definitions_parse(void) {
634 skipws(); // Skip leading whitespace
635 if (_curchar == '%' && *(_ptr+1) == '{') {
636 next_char(); next_char(); // Skip "%{"
637 skipws();
638 while (_curchar != '%' && *(_ptr+1) != '}') {
639 // Process each definition until finding closing string "%}"
640 char *token = get_ident();
641 if (token == NULL) {
642 parse_err(SYNERR, "missing identifier inside definitions block.\n");
643 return;
644 }
645 if (strcmp(token,"int_def")==0) { int_def_parse(); }
646 // if (strcmp(token,"str_def")==0) { str_def_parse(); }
647 skipws();
648 }
649 }
650 else {
651 parse_err(SYNERR, "Missing %%{ ... %%} block after definitions keyword.\n");
652 return;
653 }
654 }
655
656 //------------------------------int_def_parse----------------------------------
657 // Parse Example:
658 // int_def MEMORY_REF_COST ( 200, DEFAULT_COST * 2);
659 // <keyword> <name> ( <int_value>, <description> );
660 //
int_def_parse(void)661 void ADLParser::int_def_parse(void) {
662 char *name = NULL; // Name of definition
663 char *value = NULL; // its value,
664 int int_value = -1; // positive values only
665 char *description = NULL; // textual description
666
667 // Get definition name
668 skipws(); // Skip whitespace
669 name = get_ident();
670 if (name == NULL) {
671 parse_err(SYNERR, "missing definition name after int_def\n");
672 return;
673 }
674
675 // Check for value of int_def dname( integer_value [, string_expression ] )
676 skipws();
677 if (_curchar == '(') {
678
679 // Parse the integer value.
680 next_char();
681 value = get_ident();
682 if (value == NULL) {
683 parse_err(SYNERR, "missing value in int_def\n");
684 return;
685 }
686 if( !is_int_token(value, int_value) ) {
687 parse_err(SYNERR, "value in int_def is not recognized as integer\n");
688 return;
689 }
690 skipws();
691
692 // Check for description
693 if (_curchar == ',') {
694 next_char(); // skip ','
695
696 description = get_expr("int_def description", ")");
697 if (description == NULL) {
698 parse_err(SYNERR, "invalid or missing description in int_def\n");
699 return;
700 }
701 trim(description);
702 }
703
704 if (_curchar != ')') {
705 parse_err(SYNERR, "missing ')' in register definition statement\n");
706 return;
707 }
708 next_char();
709 }
710
711 // Check for closing ';'
712 skipws();
713 if (_curchar != ';') {
714 parse_err(SYNERR, "missing ';' after int_def\n");
715 return;
716 }
717 next_char(); // move past ';'
718
719 // Debug Stuff
720 if (_AD._adl_debug > 1) {
721 fprintf(stderr,"int_def: %s ( %s, %s )\n", name,
722 (value), (description ? description : ""));
723 }
724
725 // Record new definition.
726 Expr *expr = new Expr(name, description, int_value, int_value);
727 const Expr *old_expr = _AD.globalDefs().define(name, expr);
728 if (old_expr != NULL) {
729 parse_err(SYNERR, "Duplicate definition\n");
730 return;
731 }
732
733 return;
734 }
735
736
737 //------------------------------source_parse-----------------------------------
source_parse(void)738 void ADLParser::source_parse(void) {
739 SourceForm *source; // Encode class for instruction/operand
740 char *rule = NULL; // String representation of encode rule
741
742 skipws(); // Skip leading whitespace
743 if ( (rule = find_cpp_block("source block")) == NULL ) {
744 parse_err(SYNERR, "incorrect or missing block for 'source'.\n");
745 return;
746 }
747 // Debug Stuff
748 if (_AD._adl_debug > 1) fprintf(stderr,"Source Form: %s\n", rule);
749
750 source = new SourceForm(rule); // Build new Source object
751 _AD.addForm(source);
752 // skipws();
753 }
754
755 //------------------------------source_hpp_parse-------------------------------
756 // Parse a source_hpp %{ ... %} block.
757 // The code gets stuck into the ad_<arch>.hpp file.
758 // If the source_hpp block appears before the register block in the AD
759 // file, it goes up at the very top of the ad_<arch>.hpp file, so that
760 // it can be used by register encodings, etc. Otherwise, it goes towards
761 // the bottom, where it's useful as a global definition to *.cpp files.
source_hpp_parse(void)762 void ADLParser::source_hpp_parse(void) {
763 char *rule = NULL; // String representation of encode rule
764
765 skipws(); // Skip leading whitespace
766 if ( (rule = find_cpp_block("source_hpp block")) == NULL ) {
767 parse_err(SYNERR, "incorrect or missing block for 'source_hpp'.\n");
768 return;
769 }
770 // Debug Stuff
771 if (_AD._adl_debug > 1) fprintf(stderr,"Header Form: %s\n", rule);
772
773 if (_AD.get_registers() == NULL) {
774 // Very early in the file, before reg_defs, we collect pre-headers.
775 PreHeaderForm* pre_header = new PreHeaderForm(rule);
776 _AD.addForm(pre_header);
777 } else {
778 // Normally, we collect header info, placed at the bottom of the hpp file.
779 HeaderForm* header = new HeaderForm(rule);
780 _AD.addForm(header);
781 }
782 }
783
784 //------------------------------reg_parse--------------------------------------
reg_parse(void)785 void ADLParser::reg_parse(void) {
786 RegisterForm *regBlock = _AD.get_registers(); // Information about registers encoding
787 if (regBlock == NULL) {
788 // Create the RegisterForm for the architecture description.
789 regBlock = new RegisterForm(); // Build new Source object
790 _AD.addForm(regBlock);
791 }
792
793 skipws(); // Skip leading whitespace
794 if (_curchar == '%' && *(_ptr+1) == '{') {
795 next_char(); next_char(); // Skip "%{"
796 skipws();
797 while (_curchar != '%' && *(_ptr+1) != '}') {
798 char *token = get_ident();
799 if (token == NULL) {
800 parse_err(SYNERR, "missing identifier inside register block.\n");
801 return;
802 }
803 if (strcmp(token,"reg_def")==0) { reg_def_parse(); }
804 else if (strcmp(token,"reg_class")==0) { reg_class_parse(); }
805 else if (strcmp(token, "reg_class_dynamic") == 0) { reg_class_dynamic_parse(); }
806 else if (strcmp(token,"alloc_class")==0) { alloc_class_parse(); }
807 else if (strcmp(token,"#define")==0) { preproc_define(); }
808 else { parse_err(SYNERR, "bad token %s inside register block.\n", token); break; }
809 skipws();
810 }
811 }
812 else {
813 parse_err(SYNERR, "Missing %c{ ... %c} block after register keyword.\n",'%','%');
814 return;
815 }
816 }
817
818 //------------------------------encode_parse-----------------------------------
encode_parse(void)819 void ADLParser::encode_parse(void) {
820 EncodeForm *encBlock; // Information about instruction/operand encoding
821
822 _AD.getForm(&encBlock);
823 if ( encBlock == NULL) {
824 // Create the EncodeForm for the architecture description.
825 encBlock = new EncodeForm(); // Build new Source object
826 _AD.addForm(encBlock);
827 }
828
829 skipws(); // Skip leading whitespace
830 if (_curchar == '%' && *(_ptr+1) == '{') {
831 next_char(); next_char(); // Skip "%{"
832 skipws();
833 while (_curchar != '%' && *(_ptr+1) != '}') {
834 char *token = get_ident();
835 if (token == NULL) {
836 parse_err(SYNERR, "missing identifier inside encoding block.\n");
837 return;
838 }
839 if (strcmp(token,"enc_class")==0) { enc_class_parse(); }
840 skipws();
841 }
842 }
843 else {
844 parse_err(SYNERR, "Missing %c{ ... %c} block after encode keyword.\n",'%','%');
845 return;
846 }
847 }
848
849 //------------------------------enc_class_parse--------------------------------
enc_class_parse(void)850 void ADLParser::enc_class_parse(void) {
851 char *ec_name; // Name of encoding class being defined
852
853 // Get encoding class name
854 skipws(); // Skip whitespace
855 ec_name = get_ident();
856 if (ec_name == NULL) {
857 parse_err(SYNERR, "missing encoding class name after encode.\n");
858 return;
859 }
860
861 EncClass *encoding = _AD._encode->add_EncClass(ec_name);
862 encoding->_linenum = linenum();
863
864 skipws(); // Skip leading whitespace
865 // Check for optional parameter list
866 if (_curchar == '(') {
867 do {
868 char *pType = NULL; // parameter type
869 char *pName = NULL; // parameter name
870
871 next_char(); // skip open paren & comma characters
872 skipws();
873 if (_curchar == ')') break;
874
875 // Get parameter type
876 pType = get_ident();
877 if (pType == NULL) {
878 parse_err(SYNERR, "parameter type expected at %c\n", _curchar);
879 return;
880 }
881
882 skipws();
883 // Get parameter name
884 pName = get_ident();
885 if (pName == NULL) {
886 parse_err(SYNERR, "parameter name expected at %c\n", _curchar);
887 return;
888 }
889
890 // Record parameter type and name
891 encoding->add_parameter( pType, pName );
892
893 skipws();
894 } while(_curchar == ',');
895
896 if (_curchar != ')') parse_err(SYNERR, "missing ')'\n");
897 else {
898 next_char(); // Skip ')'
899 }
900 } // Done with parameter list
901
902 skipws();
903 // Check for block starting delimiters
904 if ((_curchar != '%') || (*(_ptr+1) != '{')) { // If not open block
905 parse_err(SYNERR, "missing '%c{' in enc_class definition\n", '%');
906 return;
907 }
908 next_char(); // Skip '%'
909 next_char(); // Skip '{'
910
911 enc_class_parse_block(encoding, ec_name);
912 }
913
914
enc_class_parse_block(EncClass * encoding,char * ec_name)915 void ADLParser::enc_class_parse_block(EncClass* encoding, char* ec_name) {
916 skipws_no_preproc(); // Skip leading whitespace
917 // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block
918 if (_AD._adlocation_debug) {
919 encoding->add_code(get_line_string());
920 }
921
922 // Collect the parts of the encode description
923 // (1) strings that are passed through to output
924 // (2) replacement/substitution variable, preceeded by a '$'
925 while ( (_curchar != '%') && (*(_ptr+1) != '}') ) {
926
927 // (1)
928 // Check if there is a string to pass through to output
929 char *start = _ptr; // Record start of the next string
930 while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {
931 // If at the start of a comment, skip past it
932 if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {
933 skipws_no_preproc();
934 } else {
935 // ELSE advance to the next character, or start of the next line
936 next_char_or_line();
937 }
938 }
939 // If a string was found, terminate it and record in EncClass
940 if ( start != _ptr ) {
941 *_ptr = '\0'; // Terminate the string
942 encoding->add_code(start);
943 }
944
945 // (2)
946 // If we are at a replacement variable,
947 // copy it and record in EncClass
948 if (_curchar == '$') {
949 // Found replacement Variable
950 char* rep_var = get_rep_var_ident_dup();
951 // Add flag to _strings list indicating we should check _rep_vars
952 encoding->add_rep_var(rep_var);
953 }
954 } // end while part of format description
955 next_char(); // Skip '%'
956 next_char(); // Skip '}'
957
958 skipws();
959
960 if (_AD._adlocation_debug) {
961 encoding->add_code(end_line_marker());
962 }
963
964 // Debug Stuff
965 if (_AD._adl_debug > 1) fprintf(stderr,"EncodingClass Form: %s\n", ec_name);
966 }
967
968 //------------------------------frame_parse-----------------------------------
frame_parse(void)969 void ADLParser::frame_parse(void) {
970 FrameForm *frame; // Information about stack-frame layout
971 char *desc = NULL; // String representation of frame
972
973 skipws(); // Skip leading whitespace
974
975 frame = new FrameForm(); // Build new Frame object
976 // Check for open block sequence
977 skipws(); // Skip leading whitespace
978 if (_curchar == '%' && *(_ptr+1) == '{') {
979 next_char(); next_char(); // Skip "%{"
980 skipws();
981 while (_curchar != '%' && *(_ptr+1) != '}') {
982 char *token = get_ident();
983 if (token == NULL) {
984 parse_err(SYNERR, "missing identifier inside frame block.\n");
985 return;
986 }
987 if (strcmp(token,"stack_direction")==0) {
988 stack_dir_parse(frame);
989 }
990 if (strcmp(token,"sync_stack_slots")==0) {
991 sync_stack_slots_parse(frame);
992 }
993 if (strcmp(token,"frame_pointer")==0) {
994 frame_pointer_parse(frame, false);
995 }
996 if (strcmp(token,"interpreter_frame_pointer")==0) {
997 interpreter_frame_pointer_parse(frame, false);
998 }
999 if (strcmp(token,"inline_cache_reg")==0) {
1000 inline_cache_parse(frame, false);
1001 }
1002 if (strcmp(token,"compiler_method_oop_reg")==0) {
1003 parse_err(WARN, "Using obsolete Token, compiler_method_oop_reg");
1004 skipws();
1005 }
1006 if (strcmp(token,"interpreter_method_oop_reg")==0) {
1007 interpreter_method_oop_parse(frame, false);
1008 }
1009 if (strcmp(token,"cisc_spilling_operand_name")==0) {
1010 cisc_spilling_operand_name_parse(frame, false);
1011 }
1012 if (strcmp(token,"stack_alignment")==0) {
1013 stack_alignment_parse(frame);
1014 }
1015 if (strcmp(token,"return_addr")==0) {
1016 return_addr_parse(frame, false);
1017 }
1018 if (strcmp(token,"in_preserve_stack_slots")==0) {
1019 preserve_stack_parse(frame);
1020 }
1021 if (strcmp(token,"out_preserve_stack_slots")==0) {
1022 parse_err(WARN, "Using obsolete token, out_preserve_stack_slots");
1023 skipws();
1024 }
1025 if (strcmp(token,"varargs_C_out_slots_killed")==0) {
1026 frame->_varargs_C_out_slots_killed = parse_one_arg("varargs C out slots killed");
1027 }
1028 if (strcmp(token,"calling_convention")==0) {
1029 frame->_calling_convention = calling_convention_parse();
1030 }
1031 if (strcmp(token,"return_value")==0) {
1032 frame->_return_value = return_value_parse();
1033 }
1034 if (strcmp(token,"c_frame_pointer")==0) {
1035 frame_pointer_parse(frame, true);
1036 }
1037 if (strcmp(token,"c_return_addr")==0) {
1038 return_addr_parse(frame, true);
1039 }
1040 if (strcmp(token,"c_calling_convention")==0) {
1041 frame->_c_calling_convention = calling_convention_parse();
1042 }
1043 if (strcmp(token,"c_return_value")==0) {
1044 frame->_c_return_value = return_value_parse();
1045 }
1046
1047 skipws();
1048 }
1049 }
1050 else {
1051 parse_err(SYNERR, "Missing %c{ ... %c} block after encode keyword.\n",'%','%');
1052 return;
1053 }
1054 // All Java versions are required, native versions are optional
1055 if(frame->_frame_pointer == NULL) {
1056 parse_err(SYNERR, "missing frame pointer definition in frame section.\n");
1057 return;
1058 }
1059 // !!!!! !!!!!
1060 // if(frame->_interpreter_frame_ptr_reg == NULL) {
1061 // parse_err(SYNERR, "missing interpreter frame pointer definition in frame section.\n");
1062 // return;
1063 // }
1064 if(frame->_alignment == NULL) {
1065 parse_err(SYNERR, "missing alignment definition in frame section.\n");
1066 return;
1067 }
1068 if(frame->_return_addr == NULL) {
1069 parse_err(SYNERR, "missing return address location in frame section.\n");
1070 return;
1071 }
1072 if(frame->_in_preserve_slots == NULL) {
1073 parse_err(SYNERR, "missing stack slot preservation definition in frame section.\n");
1074 return;
1075 }
1076 if(frame->_varargs_C_out_slots_killed == NULL) {
1077 parse_err(SYNERR, "missing varargs C out slots killed definition in frame section.\n");
1078 return;
1079 }
1080 if(frame->_calling_convention == NULL) {
1081 parse_err(SYNERR, "missing calling convention definition in frame section.\n");
1082 return;
1083 }
1084 if(frame->_return_value == NULL) {
1085 parse_err(SYNERR, "missing return value definition in frame section.\n");
1086 return;
1087 }
1088 // Fill natives in identically with the Java versions if not present.
1089 if(frame->_c_frame_pointer == NULL) {
1090 frame->_c_frame_pointer = frame->_frame_pointer;
1091 }
1092 if(frame->_c_return_addr == NULL) {
1093 frame->_c_return_addr = frame->_return_addr;
1094 frame->_c_return_addr_loc = frame->_return_addr_loc;
1095 }
1096 if(frame->_c_calling_convention == NULL) {
1097 frame->_c_calling_convention = frame->_calling_convention;
1098 }
1099 if(frame->_c_return_value == NULL) {
1100 frame->_c_return_value = frame->_return_value;
1101 }
1102
1103 // Debug Stuff
1104 if (_AD._adl_debug > 1) fprintf(stderr,"Frame Form: %s\n", desc);
1105
1106 // Create the EncodeForm for the architecture description.
1107 _AD.addForm(frame);
1108 // skipws();
1109 }
1110
1111 //------------------------------stack_dir_parse--------------------------------
stack_dir_parse(FrameForm * frame)1112 void ADLParser::stack_dir_parse(FrameForm *frame) {
1113 char *direction = parse_one_arg("stack direction entry");
1114 if (strcmp(direction, "TOWARDS_LOW") == 0) {
1115 frame->_direction = false;
1116 }
1117 else if (strcmp(direction, "TOWARDS_HIGH") == 0) {
1118 frame->_direction = true;
1119 }
1120 else {
1121 parse_err(SYNERR, "invalid value inside stack direction entry.\n");
1122 return;
1123 }
1124 }
1125
1126 //------------------------------sync_stack_slots_parse-------------------------
sync_stack_slots_parse(FrameForm * frame)1127 void ADLParser::sync_stack_slots_parse(FrameForm *frame) {
1128 // Assign value into frame form
1129 frame->_sync_stack_slots = parse_one_arg("sync stack slots entry");
1130 }
1131
1132 //------------------------------frame_pointer_parse----------------------------
frame_pointer_parse(FrameForm * frame,bool native)1133 void ADLParser::frame_pointer_parse(FrameForm *frame, bool native) {
1134 char *frame_pointer = parse_one_arg("frame pointer entry");
1135 // Assign value into frame form
1136 if (native) { frame->_c_frame_pointer = frame_pointer; }
1137 else { frame->_frame_pointer = frame_pointer; }
1138 }
1139
1140 //------------------------------interpreter_frame_pointer_parse----------------------------
interpreter_frame_pointer_parse(FrameForm * frame,bool native)1141 void ADLParser::interpreter_frame_pointer_parse(FrameForm *frame, bool native) {
1142 frame->_interpreter_frame_pointer_reg = parse_one_arg("interpreter frame pointer entry");
1143 }
1144
1145 //------------------------------inline_cache_parse-----------------------------
inline_cache_parse(FrameForm * frame,bool native)1146 void ADLParser::inline_cache_parse(FrameForm *frame, bool native) {
1147 frame->_inline_cache_reg = parse_one_arg("inline cache reg entry");
1148 }
1149
1150 //------------------------------interpreter_method_oop_parse------------------
interpreter_method_oop_parse(FrameForm * frame,bool native)1151 void ADLParser::interpreter_method_oop_parse(FrameForm *frame, bool native) {
1152 frame->_interpreter_method_oop_reg = parse_one_arg("method oop reg entry");
1153 }
1154
1155 //------------------------------cisc_spilling_operand_parse---------------------
cisc_spilling_operand_name_parse(FrameForm * frame,bool native)1156 void ADLParser::cisc_spilling_operand_name_parse(FrameForm *frame, bool native) {
1157 frame->_cisc_spilling_operand_name = parse_one_arg("cisc spilling operand name");
1158 }
1159
1160 //------------------------------stack_alignment_parse--------------------------
stack_alignment_parse(FrameForm * frame)1161 void ADLParser::stack_alignment_parse(FrameForm *frame) {
1162 char *alignment = parse_one_arg("stack alignment entry");
1163 // Assign value into frame
1164 frame->_alignment = alignment;
1165 }
1166
1167 //------------------------------parse_one_arg-------------------------------
parse_one_arg(const char * description)1168 char *ADLParser::parse_one_arg(const char *description) {
1169 char *token = NULL;
1170 if(_curchar == '(') {
1171 next_char();
1172 skipws();
1173 token = get_expr(description, ")");
1174 if (token == NULL) {
1175 parse_err(SYNERR, "missing value inside %s.\n", description);
1176 return NULL;
1177 }
1178 next_char(); // skip the close paren
1179 if(_curchar != ';') { // check for semi-colon
1180 parse_err(SYNERR, "missing %c in.\n", ';', description);
1181 return NULL;
1182 }
1183 next_char(); // skip the semi-colon
1184 }
1185 else {
1186 parse_err(SYNERR, "Missing %c in.\n", '(', description);
1187 return NULL;
1188 }
1189
1190 trim(token);
1191 return token;
1192 }
1193
1194 //------------------------------return_addr_parse------------------------------
return_addr_parse(FrameForm * frame,bool native)1195 void ADLParser::return_addr_parse(FrameForm *frame, bool native) {
1196 bool in_register = true;
1197 if(_curchar == '(') {
1198 next_char();
1199 skipws();
1200 char *token = get_ident();
1201 if (token == NULL) {
1202 parse_err(SYNERR, "missing value inside return address entry.\n");
1203 return;
1204 }
1205 // check for valid values for stack/register
1206 if (strcmp(token, "REG") == 0) {
1207 in_register = true;
1208 }
1209 else if (strcmp(token, "STACK") == 0) {
1210 in_register = false;
1211 }
1212 else {
1213 parse_err(SYNERR, "invalid value inside return_address entry.\n");
1214 return;
1215 }
1216 if (native) { frame->_c_return_addr_loc = in_register; }
1217 else { frame->_return_addr_loc = in_register; }
1218
1219 // Parse expression that specifies register or stack position
1220 skipws();
1221 char *token2 = get_expr("return address entry", ")");
1222 if (token2 == NULL) {
1223 parse_err(SYNERR, "missing value inside return address entry.\n");
1224 return;
1225 }
1226 next_char(); // skip the close paren
1227 if (native) { frame->_c_return_addr = token2; }
1228 else { frame->_return_addr = token2; }
1229
1230 if(_curchar != ';') { // check for semi-colon
1231 parse_err(SYNERR, "missing %c in return address entry.\n", ';');
1232 return;
1233 }
1234 next_char(); // skip the semi-colon
1235 }
1236 else {
1237 parse_err(SYNERR, "Missing %c in return_address entry.\n", '(');
1238 }
1239 }
1240
1241 //------------------------------preserve_stack_parse---------------------------
preserve_stack_parse(FrameForm * frame)1242 void ADLParser::preserve_stack_parse(FrameForm *frame) {
1243 if(_curchar == '(') {
1244 char *token = get_paren_expr("preserve_stack_slots");
1245 frame->_in_preserve_slots = token;
1246
1247 if(_curchar != ';') { // check for semi-colon
1248 parse_err(SYNERR, "missing %c in preserve stack slot entry.\n", ';');
1249 return;
1250 }
1251 next_char(); // skip the semi-colon
1252 }
1253 else {
1254 parse_err(SYNERR, "Missing %c in preserve stack slot entry.\n", '(');
1255 }
1256 }
1257
1258 //------------------------------calling_convention_parse-----------------------
calling_convention_parse()1259 char *ADLParser::calling_convention_parse() {
1260 char *desc = NULL; // String representation of calling_convention
1261
1262 skipws(); // Skip leading whitespace
1263 if ( (desc = find_cpp_block("calling convention block")) == NULL ) {
1264 parse_err(SYNERR, "incorrect or missing block for 'calling_convention'.\n");
1265 }
1266 return desc;
1267 }
1268
1269 //------------------------------return_value_parse-----------------------------
return_value_parse()1270 char *ADLParser::return_value_parse() {
1271 char *desc = NULL; // String representation of calling_convention
1272
1273 skipws(); // Skip leading whitespace
1274 if ( (desc = find_cpp_block("return value block")) == NULL ) {
1275 parse_err(SYNERR, "incorrect or missing block for 'return_value'.\n");
1276 }
1277 return desc;
1278 }
1279
1280 //------------------------------ins_pipe_parse---------------------------------
ins_pipe_parse(InstructForm & instr)1281 void ADLParser::ins_pipe_parse(InstructForm &instr) {
1282 char * ident;
1283
1284 skipws();
1285 if ( _curchar != '(' ) { // Check for delimiter
1286 parse_err(SYNERR, "missing \"(\" in ins_pipe definition\n");
1287 return;
1288 }
1289
1290 next_char();
1291 ident = get_ident(); // Grab next identifier
1292
1293 if (ident == NULL) {
1294 parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);
1295 return;
1296 }
1297
1298 skipws();
1299 if ( _curchar != ')' ) { // Check for delimiter
1300 parse_err(SYNERR, "missing \")\" in ins_pipe definition\n");
1301 return;
1302 }
1303
1304 next_char(); // skip the close paren
1305 if(_curchar != ';') { // check for semi-colon
1306 parse_err(SYNERR, "missing %c in return value entry.\n", ';');
1307 return;
1308 }
1309 next_char(); // skip the semi-colon
1310
1311 // Check ident for validity
1312 if (_AD._pipeline && !_AD._pipeline->_classlist.search(ident)) {
1313 parse_err(SYNERR, "\"%s\" is not a valid pipeline class\n", ident);
1314 return;
1315 }
1316
1317 // Add this instruction to the list in the pipeline class
1318 _AD._pipeline->_classdict[ident]->is_pipeclass()->_instructs.addName(instr._ident);
1319
1320 // Set the name of the pipeline class in the instruction
1321 instr._ins_pipe = ident;
1322 return;
1323 }
1324
1325 //------------------------------pipe_parse-------------------------------------
pipe_parse(void)1326 void ADLParser::pipe_parse(void) {
1327 PipelineForm *pipeline; // Encode class for instruction/operand
1328 char * ident;
1329
1330 pipeline = new PipelineForm(); // Build new Source object
1331 _AD.addForm(pipeline);
1332
1333 skipws(); // Skip leading whitespace
1334 // Check for block delimiter
1335 if ( (_curchar != '%')
1336 || ( next_char(), (_curchar != '{')) ) {
1337 parse_err(SYNERR, "missing '%%{' in pipeline definition\n");
1338 return;
1339 }
1340 next_char(); // Maintain the invariant
1341 do {
1342 ident = get_ident(); // Grab next identifier
1343 if (ident == NULL) {
1344 parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);
1345 continue;
1346 }
1347 if (!strcmp(ident, "resources" )) resource_parse(*pipeline);
1348 else if (!strcmp(ident, "pipe_desc" )) pipe_desc_parse(*pipeline);
1349 else if (!strcmp(ident, "pipe_class")) pipe_class_parse(*pipeline);
1350 else if (!strcmp(ident, "define")) {
1351 skipws();
1352 if ( (_curchar != '%')
1353 || ( next_char(), (_curchar != '{')) ) {
1354 parse_err(SYNERR, "expected '%%{'\n");
1355 return;
1356 }
1357 next_char(); skipws();
1358
1359 char *node_class = get_ident();
1360 if (node_class == NULL) {
1361 parse_err(SYNERR, "expected identifier, found \"%c\"\n", _curchar);
1362 return;
1363 }
1364
1365 skipws();
1366 if (_curchar != ',' && _curchar != '=') {
1367 parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);
1368 break;
1369 }
1370 next_char(); skipws();
1371
1372 char *pipe_class = get_ident();
1373 if (pipe_class == NULL) {
1374 parse_err(SYNERR, "expected identifier, found \"%c\"\n", _curchar);
1375 return;
1376 }
1377 if (_curchar != ';' ) {
1378 parse_err(SYNERR, "expected `;`, found '%c'\n", _curchar);
1379 break;
1380 }
1381 next_char(); // Skip over semi-colon
1382
1383 skipws();
1384 if ( (_curchar != '%')
1385 || ( next_char(), (_curchar != '}')) ) {
1386 parse_err(SYNERR, "expected '%%}', found \"%c\"\n", _curchar);
1387 }
1388 next_char();
1389
1390 // Check ident for validity
1391 if (_AD._pipeline && !_AD._pipeline->_classlist.search(pipe_class)) {
1392 parse_err(SYNERR, "\"%s\" is not a valid pipeline class\n", pipe_class);
1393 return;
1394 }
1395
1396 // Add this machine node to the list in the pipeline class
1397 _AD._pipeline->_classdict[pipe_class]->is_pipeclass()->_instructs.addName(node_class);
1398
1399 MachNodeForm *machnode = new MachNodeForm(node_class); // Create new machnode form
1400 machnode->_machnode_pipe = pipe_class;
1401
1402 _AD.addForm(machnode);
1403 }
1404 else if (!strcmp(ident, "attributes")) {
1405 bool vsi_seen = false;
1406
1407 skipws();
1408 if ( (_curchar != '%')
1409 || ( next_char(), (_curchar != '{')) ) {
1410 parse_err(SYNERR, "expected '%%{'\n");
1411 return;
1412 }
1413 next_char(); skipws();
1414
1415 while (_curchar != '%') {
1416 ident = get_ident();
1417 if (ident == NULL)
1418 break;
1419
1420 if (!strcmp(ident, "variable_size_instructions")) {
1421 skipws();
1422 if (_curchar == ';') {
1423 next_char(); skipws();
1424 }
1425
1426 pipeline->_variableSizeInstrs = true;
1427 vsi_seen = true;
1428 continue;
1429 }
1430
1431 if (!strcmp(ident, "fixed_size_instructions")) {
1432 skipws();
1433 if (_curchar == ';') {
1434 next_char(); skipws();
1435 }
1436
1437 pipeline->_variableSizeInstrs = false;
1438 vsi_seen = true;
1439 continue;
1440 }
1441
1442 if (!strcmp(ident, "branch_has_delay_slot")) {
1443 skipws();
1444 if (_curchar == ';') {
1445 next_char(); skipws();
1446 }
1447
1448 pipeline->_branchHasDelaySlot = true;
1449 continue;
1450 }
1451
1452 if (!strcmp(ident, "max_instructions_per_bundle")) {
1453 skipws();
1454 if (_curchar != '=') {
1455 parse_err(SYNERR, "expected `=`\n");
1456 break;
1457 }
1458
1459 next_char(); skipws();
1460 pipeline->_maxInstrsPerBundle = get_int();
1461 skipws();
1462
1463 if (_curchar == ';') {
1464 next_char(); skipws();
1465 }
1466
1467 continue;
1468 }
1469
1470 if (!strcmp(ident, "max_bundles_per_cycle")) {
1471 skipws();
1472 if (_curchar != '=') {
1473 parse_err(SYNERR, "expected `=`\n");
1474 break;
1475 }
1476
1477 next_char(); skipws();
1478 pipeline->_maxBundlesPerCycle = get_int();
1479 skipws();
1480
1481 if (_curchar == ';') {
1482 next_char(); skipws();
1483 }
1484
1485 continue;
1486 }
1487
1488 if (!strcmp(ident, "instruction_unit_size")) {
1489 skipws();
1490 if (_curchar != '=') {
1491 parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);
1492 break;
1493 }
1494
1495 next_char(); skipws();
1496 pipeline->_instrUnitSize = get_int();
1497 skipws();
1498
1499 if (_curchar == ';') {
1500 next_char(); skipws();
1501 }
1502
1503 continue;
1504 }
1505
1506 if (!strcmp(ident, "bundle_unit_size")) {
1507 skipws();
1508 if (_curchar != '=') {
1509 parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);
1510 break;
1511 }
1512
1513 next_char(); skipws();
1514 pipeline->_bundleUnitSize = get_int();
1515 skipws();
1516
1517 if (_curchar == ';') {
1518 next_char(); skipws();
1519 }
1520
1521 continue;
1522 }
1523
1524 if (!strcmp(ident, "instruction_fetch_unit_size")) {
1525 skipws();
1526 if (_curchar != '=') {
1527 parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);
1528 break;
1529 }
1530
1531 next_char(); skipws();
1532 pipeline->_instrFetchUnitSize = get_int();
1533 skipws();
1534
1535 if (_curchar == ';') {
1536 next_char(); skipws();
1537 }
1538
1539 continue;
1540 }
1541
1542 if (!strcmp(ident, "instruction_fetch_units")) {
1543 skipws();
1544 if (_curchar != '=') {
1545 parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);
1546 break;
1547 }
1548
1549 next_char(); skipws();
1550 pipeline->_instrFetchUnits = get_int();
1551 skipws();
1552
1553 if (_curchar == ';') {
1554 next_char(); skipws();
1555 }
1556
1557 continue;
1558 }
1559
1560 if (!strcmp(ident, "nops")) {
1561 skipws();
1562 if (_curchar != '(') {
1563 parse_err(SYNERR, "expected `(`, found '%c'\n", _curchar);
1564 break;
1565 }
1566
1567 next_char(); skipws();
1568
1569 while (_curchar != ')') {
1570 ident = get_ident();
1571 if (ident == NULL) {
1572 parse_err(SYNERR, "expected identifier for nop instruction, found '%c'\n", _curchar);
1573 break;
1574 }
1575
1576 pipeline->_noplist.addName(ident);
1577 pipeline->_nopcnt++;
1578 skipws();
1579
1580 if (_curchar == ',') {
1581 next_char(); skipws();
1582 }
1583 }
1584
1585 next_char(); skipws();
1586
1587 if (_curchar == ';') {
1588 next_char(); skipws();
1589 }
1590
1591 continue;
1592 }
1593
1594 parse_err(SYNERR, "unknown specifier \"%s\"\n", ident);
1595 }
1596
1597 if ( (_curchar != '%')
1598 || ( next_char(), (_curchar != '}')) ) {
1599 parse_err(SYNERR, "expected '%%}', found \"%c\"\n", _curchar);
1600 }
1601 next_char(); skipws();
1602
1603 if (pipeline->_maxInstrsPerBundle == 0)
1604 parse_err(SYNERR, "\"max_instructions_per_bundle\" unspecified\n");
1605 if (pipeline->_instrUnitSize == 0 && pipeline->_bundleUnitSize == 0)
1606 parse_err(SYNERR, "\"instruction_unit_size\" and \"bundle_unit_size\" unspecified\n");
1607 if (pipeline->_instrFetchUnitSize == 0)
1608 parse_err(SYNERR, "\"instruction_fetch_unit_size\" unspecified\n");
1609 if (pipeline->_instrFetchUnits == 0)
1610 parse_err(SYNERR, "\"instruction_fetch_units\" unspecified\n");
1611 if (!vsi_seen)
1612 parse_err(SYNERR, "\"variable_size_instruction\" or \"fixed_size_instruction\" unspecified\n");
1613 }
1614 else { // Done with staticly defined parts of instruction definition
1615 parse_err(SYNERR, "expected one of \"resources\", \"pipe_desc\", \"pipe_class\", found \"%s\"\n", ident);
1616 return;
1617 }
1618 skipws();
1619 if (_curchar == ';')
1620 skipws();
1621 } while(_curchar != '%');
1622
1623 next_char();
1624 if (_curchar != '}') {
1625 parse_err(SYNERR, "missing \"%%}\" in pipeline definition\n");
1626 return;
1627 }
1628
1629 next_char();
1630 }
1631
1632 //------------------------------resource_parse----------------------------
resource_parse(PipelineForm & pipeline)1633 void ADLParser::resource_parse(PipelineForm &pipeline) {
1634 ResourceForm *resource;
1635 char * ident;
1636 char * expr;
1637 unsigned mask;
1638 pipeline._rescount = 0;
1639
1640 skipws(); // Skip leading whitespace
1641
1642 if (_curchar != '(') {
1643 parse_err(SYNERR, "missing \"(\" in resource definition\n");
1644 return;
1645 }
1646
1647 do {
1648 next_char(); // Skip "(" or ","
1649 ident = get_ident(); // Grab next identifier
1650
1651 if (_AD._adl_debug > 1) {
1652 if (ident != NULL) {
1653 fprintf(stderr, "resource_parse: identifier: %s\n", ident);
1654 }
1655 }
1656
1657 if (ident == NULL) {
1658 parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);
1659 return;
1660 }
1661 skipws();
1662
1663 if (_curchar != '=') {
1664 mask = (1 << pipeline._rescount++);
1665 }
1666 else {
1667 next_char(); skipws();
1668 expr = get_ident(); // Grab next identifier
1669 if (expr == NULL) {
1670 parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);
1671 return;
1672 }
1673 resource = (ResourceForm *) pipeline._resdict[expr];
1674 if (resource == NULL) {
1675 parse_err(SYNERR, "resource \"%s\" is not defined\n", expr);
1676 return;
1677 }
1678 mask = resource->mask();
1679
1680 skipws();
1681 while (_curchar == '|') {
1682 next_char(); skipws();
1683
1684 expr = get_ident(); // Grab next identifier
1685 if (expr == NULL) {
1686 parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);
1687 return;
1688 }
1689
1690 resource = (ResourceForm *) pipeline._resdict[expr]; // Look up the value
1691 if (resource == NULL) {
1692 parse_err(SYNERR, "resource \"%s\" is not defined\n", expr);
1693 return;
1694 }
1695
1696 mask |= resource->mask();
1697 skipws();
1698 }
1699 }
1700
1701 resource = new ResourceForm(mask);
1702
1703 pipeline._resdict.Insert(ident, resource);
1704 pipeline._reslist.addName(ident);
1705 } while (_curchar == ',');
1706
1707 if (_curchar != ')') {
1708 parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);
1709 return;
1710 }
1711
1712 next_char(); // Skip ")"
1713 if (_curchar == ';')
1714 next_char(); // Skip ";"
1715 }
1716
1717 //------------------------------resource_parse----------------------------
pipe_desc_parse(PipelineForm & pipeline)1718 void ADLParser::pipe_desc_parse(PipelineForm &pipeline) {
1719 char * ident;
1720
1721 skipws(); // Skip leading whitespace
1722
1723 if (_curchar != '(') {
1724 parse_err(SYNERR, "missing \"(\" in pipe_desc definition\n");
1725 return;
1726 }
1727
1728 do {
1729 next_char(); // Skip "(" or ","
1730 ident = get_ident(); // Grab next identifier
1731 if (ident == NULL) {
1732 parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);
1733 return;
1734 }
1735
1736 // Add the name to the list
1737 pipeline._stages.addName(ident);
1738 pipeline._stagecnt++;
1739
1740 skipws();
1741 } while (_curchar == ',');
1742
1743 if (_curchar != ')') {
1744 parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);
1745 return;
1746 }
1747
1748 next_char(); // Skip ")"
1749 if (_curchar == ';')
1750 next_char(); // Skip ";"
1751 }
1752
1753 //------------------------------pipe_class_parse--------------------------
pipe_class_parse(PipelineForm & pipeline)1754 void ADLParser::pipe_class_parse(PipelineForm &pipeline) {
1755 PipeClassForm *pipe_class;
1756 char * ident;
1757 char * stage;
1758 char * read_or_write;
1759 int is_write;
1760 int is_read;
1761 OperandForm *oper;
1762
1763 skipws(); // Skip leading whitespace
1764
1765 ident = get_ident(); // Grab next identifier
1766
1767 if (ident == NULL) {
1768 parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);
1769 return;
1770 }
1771
1772 // Create a record for the pipe_class
1773 pipe_class = new PipeClassForm(ident, ++pipeline._classcnt);
1774 pipeline._classdict.Insert(ident, pipe_class);
1775 pipeline._classlist.addName(ident);
1776
1777 // Then get the operands
1778 skipws();
1779 if (_curchar != '(') {
1780 parse_err(SYNERR, "missing \"(\" in pipe_class definition\n");
1781 }
1782 // Parse the operand list
1783 else get_oplist(pipe_class->_parameters, pipe_class->_localNames);
1784 skipws(); // Skip leading whitespace
1785 // Check for block delimiter
1786 if ( (_curchar != '%')
1787 || ( next_char(), (_curchar != '{')) ) {
1788 parse_err(SYNERR, "missing \"%%{\" in pipe_class definition\n");
1789 return;
1790 }
1791 next_char();
1792
1793 do {
1794 ident = get_ident(); // Grab next identifier
1795 if (ident == NULL) {
1796 parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);
1797 continue;
1798 }
1799 skipws();
1800
1801 if (!strcmp(ident, "fixed_latency")) {
1802 skipws();
1803 if (_curchar != '(') {
1804 parse_err(SYNERR, "missing \"(\" in latency definition\n");
1805 return;
1806 }
1807 next_char(); skipws();
1808 if( !isdigit(_curchar) ) {
1809 parse_err(SYNERR, "number expected for \"%c\" in latency definition\n", _curchar);
1810 return;
1811 }
1812 int fixed_latency = get_int();
1813 skipws();
1814 if (_curchar != ')') {
1815 parse_err(SYNERR, "missing \")\" in latency definition\n");
1816 return;
1817 }
1818 next_char(); skipws();
1819 if (_curchar != ';') {
1820 parse_err(SYNERR, "missing \";\" in latency definition\n");
1821 return;
1822 }
1823
1824 pipe_class->setFixedLatency(fixed_latency);
1825 next_char(); skipws();
1826 continue;
1827 }
1828
1829 if (!strcmp(ident, "zero_instructions") ||
1830 !strcmp(ident, "no_instructions")) {
1831 skipws();
1832 if (_curchar != ';') {
1833 parse_err(SYNERR, "missing \";\" in latency definition\n");
1834 return;
1835 }
1836
1837 pipe_class->setInstructionCount(0);
1838 next_char(); skipws();
1839 continue;
1840 }
1841
1842 if (!strcmp(ident, "one_instruction_with_delay_slot") ||
1843 !strcmp(ident, "single_instruction_with_delay_slot")) {
1844 skipws();
1845 if (_curchar != ';') {
1846 parse_err(SYNERR, "missing \";\" in latency definition\n");
1847 return;
1848 }
1849
1850 pipe_class->setInstructionCount(1);
1851 pipe_class->setBranchDelay(true);
1852 next_char(); skipws();
1853 continue;
1854 }
1855
1856 if (!strcmp(ident, "one_instruction") ||
1857 !strcmp(ident, "single_instruction")) {
1858 skipws();
1859 if (_curchar != ';') {
1860 parse_err(SYNERR, "missing \";\" in latency definition\n");
1861 return;
1862 }
1863
1864 pipe_class->setInstructionCount(1);
1865 next_char(); skipws();
1866 continue;
1867 }
1868
1869 if (!strcmp(ident, "instructions_in_first_bundle") ||
1870 !strcmp(ident, "instruction_count")) {
1871 skipws();
1872
1873 int number_of_instructions = 1;
1874
1875 if (_curchar != '(') {
1876 parse_err(SYNERR, "\"(\" expected at \"%c\"\n", _curchar);
1877 continue;
1878 }
1879
1880 next_char(); skipws();
1881 number_of_instructions = get_int();
1882
1883 skipws();
1884 if (_curchar != ')') {
1885 parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);
1886 continue;
1887 }
1888
1889 next_char(); skipws();
1890 if (_curchar != ';') {
1891 parse_err(SYNERR, "missing \";\" in latency definition\n");
1892 return;
1893 }
1894
1895 pipe_class->setInstructionCount(number_of_instructions);
1896 next_char(); skipws();
1897 continue;
1898 }
1899
1900 if (!strcmp(ident, "multiple_bundles")) {
1901 skipws();
1902 if (_curchar != ';') {
1903 parse_err(SYNERR, "missing \";\" after multiple bundles\n");
1904 return;
1905 }
1906
1907 pipe_class->setMultipleBundles(true);
1908 next_char(); skipws();
1909 continue;
1910 }
1911
1912 if (!strcmp(ident, "has_delay_slot")) {
1913 skipws();
1914 if (_curchar != ';') {
1915 parse_err(SYNERR, "missing \";\" after \"has_delay_slot\"\n");
1916 return;
1917 }
1918
1919 pipe_class->setBranchDelay(true);
1920 next_char(); skipws();
1921 continue;
1922 }
1923
1924 if (!strcmp(ident, "force_serialization")) {
1925 skipws();
1926 if (_curchar != ';') {
1927 parse_err(SYNERR, "missing \";\" after \"force_serialization\"\n");
1928 return;
1929 }
1930
1931 pipe_class->setForceSerialization(true);
1932 next_char(); skipws();
1933 continue;
1934 }
1935
1936 if (!strcmp(ident, "may_have_no_code")) {
1937 skipws();
1938 if (_curchar != ';') {
1939 parse_err(SYNERR, "missing \";\" after \"may_have_no_code\"\n");
1940 return;
1941 }
1942
1943 pipe_class->setMayHaveNoCode(true);
1944 next_char(); skipws();
1945 continue;
1946 }
1947
1948 const Form *parm = pipe_class->_localNames[ident];
1949 if (parm != NULL) {
1950 oper = parm->is_operand();
1951 if (oper == NULL && !parm->is_opclass()) {
1952 parse_err(SYNERR, "operand name expected at %s\n", ident);
1953 continue;
1954 }
1955
1956 if (_curchar != ':') {
1957 parse_err(SYNERR, "\":\" expected at \"%c\"\n", _curchar);
1958 continue;
1959 }
1960 next_char(); skipws();
1961 stage = get_ident();
1962 if (stage == NULL) {
1963 parse_err(SYNERR, "pipeline stage identifier expected at \"%c\"\n", _curchar);
1964 continue;
1965 }
1966
1967 skipws();
1968 if (_curchar != '(') {
1969 parse_err(SYNERR, "\"(\" expected at \"%c\"\n", _curchar);
1970 continue;
1971 }
1972
1973 next_char();
1974 read_or_write = get_ident();
1975 if (read_or_write == NULL) {
1976 parse_err(SYNERR, "\"read\" or \"write\" expected at \"%c\"\n", _curchar);
1977 continue;
1978 }
1979
1980 is_read = strcmp(read_or_write, "read") == 0;
1981 is_write = strcmp(read_or_write, "write") == 0;
1982 if (!is_read && !is_write) {
1983 parse_err(SYNERR, "\"read\" or \"write\" expected at \"%c\"\n", _curchar);
1984 continue;
1985 }
1986
1987 skipws();
1988 if (_curchar != ')') {
1989 parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);
1990 continue;
1991 }
1992
1993 next_char(); skipws();
1994 int more_instrs = 0;
1995 if (_curchar == '+') {
1996 next_char(); skipws();
1997 if (_curchar < '0' || _curchar > '9') {
1998 parse_err(SYNERR, "<number> expected at \"%c\"\n", _curchar);
1999 continue;
2000 }
2001 while (_curchar >= '0' && _curchar <= '9') {
2002 more_instrs *= 10;
2003 more_instrs += _curchar - '0';
2004 next_char();
2005 }
2006 skipws();
2007 }
2008
2009 PipeClassOperandForm *pipe_operand = new PipeClassOperandForm(stage, is_write, more_instrs);
2010 pipe_class->_localUsage.Insert(ident, pipe_operand);
2011
2012 if (_curchar == '%')
2013 continue;
2014
2015 if (_curchar != ';') {
2016 parse_err(SYNERR, "\";\" expected at \"%c\"\n", _curchar);
2017 continue;
2018 }
2019 next_char(); skipws();
2020 continue;
2021 }
2022
2023 // Scan for Resource Specifier
2024 const Form *res = pipeline._resdict[ident];
2025 if (res != NULL) {
2026 int cyclecnt = 1;
2027 if (_curchar != ':') {
2028 parse_err(SYNERR, "\":\" expected at \"%c\"\n", _curchar);
2029 continue;
2030 }
2031 next_char(); skipws();
2032 stage = get_ident();
2033 if (stage == NULL) {
2034 parse_err(SYNERR, "pipeline stage identifier expected at \"%c\"\n", _curchar);
2035 continue;
2036 }
2037
2038 skipws();
2039 if (_curchar == '(') {
2040 next_char();
2041 cyclecnt = get_int();
2042
2043 skipws();
2044 if (_curchar != ')') {
2045 parse_err(SYNERR, "\")\" expected at \"%c\"\n", _curchar);
2046 continue;
2047 }
2048
2049 next_char(); skipws();
2050 }
2051
2052 PipeClassResourceForm *resource = new PipeClassResourceForm(ident, stage, cyclecnt);
2053 int stagenum = pipeline._stages.index(stage);
2054 if (pipeline._maxcycleused < (stagenum+cyclecnt))
2055 pipeline._maxcycleused = (stagenum+cyclecnt);
2056 pipe_class->_resUsage.addForm(resource);
2057
2058 if (_curchar == '%')
2059 continue;
2060
2061 if (_curchar != ';') {
2062 parse_err(SYNERR, "\";\" expected at \"%c\"\n", _curchar);
2063 continue;
2064 }
2065 next_char(); skipws();
2066 continue;
2067 }
2068
2069 parse_err(SYNERR, "resource expected at \"%s\"\n", ident);
2070 return;
2071 } while(_curchar != '%');
2072
2073 next_char();
2074 if (_curchar != '}') {
2075 parse_err(SYNERR, "missing \"%%}\" in pipe_class definition\n");
2076 return;
2077 }
2078
2079 next_char();
2080 }
2081
2082 //------------------------------peep_parse-------------------------------------
peep_parse(void)2083 void ADLParser::peep_parse(void) {
2084 Peephole *peep; // Pointer to current peephole rule form
2085 char *desc = NULL; // String representation of rule
2086
2087 skipws(); // Skip leading whitespace
2088
2089 peep = new Peephole(); // Build new Peephole object
2090 // Check for open block sequence
2091 skipws(); // Skip leading whitespace
2092 if (_curchar == '%' && *(_ptr+1) == '{') {
2093 next_char(); next_char(); // Skip "%{"
2094 skipws();
2095 while (_curchar != '%' && *(_ptr+1) != '}') {
2096 char *token = get_ident();
2097 if (token == NULL) {
2098 parse_err(SYNERR, "missing identifier inside peephole rule.\n");
2099 return;
2100 }
2101 // check for legal subsections of peephole rule
2102 if (strcmp(token,"peepmatch")==0) {
2103 peep_match_parse(*peep); }
2104 else if (strcmp(token,"peepconstraint")==0) {
2105 peep_constraint_parse(*peep); }
2106 else if (strcmp(token,"peepreplace")==0) {
2107 peep_replace_parse(*peep); }
2108 else {
2109 parse_err(SYNERR, "expected peepmatch, peepconstraint, or peepreplace for identifier %s.\n", token);
2110 }
2111 skipws();
2112 }
2113 }
2114 else {
2115 parse_err(SYNERR, "Missing %%{ ... %%} block after peephole keyword.\n");
2116 return;
2117 }
2118 next_char(); // Skip past '%'
2119 next_char(); // Skip past '}'
2120 }
2121
2122 // ******************** Private Level 2 Parse Functions ********************
2123 //------------------------------constraint_parse------------------------------
constraint_parse(void)2124 Constraint *ADLParser::constraint_parse(void) {
2125 char *func;
2126 char *arg;
2127
2128 // Check for constraint expression
2129 skipws();
2130 if (_curchar != '(') {
2131 parse_err(SYNERR, "missing constraint expression, (...)\n");
2132 return NULL;
2133 }
2134 next_char(); // Skip past '('
2135
2136 // Get constraint function
2137 skipws();
2138 func = get_ident();
2139 if (func == NULL) {
2140 parse_err(SYNERR, "missing function in constraint expression.\n");
2141 return NULL;
2142 }
2143 if (strcmp(func,"ALLOC_IN_RC")==0
2144 || strcmp(func,"IS_R_CLASS")==0) {
2145 // Check for '(' before argument
2146 skipws();
2147 if (_curchar != '(') {
2148 parse_err(SYNERR, "missing '(' for constraint function's argument.\n");
2149 return NULL;
2150 }
2151 next_char();
2152
2153 // Get it's argument
2154 skipws();
2155 arg = get_ident();
2156 if (arg == NULL) {
2157 parse_err(SYNERR, "missing argument for constraint function %s\n",func);
2158 return NULL;
2159 }
2160 // Check for ')' after argument
2161 skipws();
2162 if (_curchar != ')') {
2163 parse_err(SYNERR, "missing ')' after constraint function argument %s\n",arg);
2164 return NULL;
2165 }
2166 next_char();
2167 } else {
2168 parse_err(SYNERR, "Invalid constraint function %s\n",func);
2169 return NULL;
2170 }
2171
2172 // Check for closing paren and ';'
2173 skipws();
2174 if (_curchar != ')') {
2175 parse_err(SYNERR, "Missing ')' for constraint function %s\n",func);
2176 return NULL;
2177 }
2178 next_char();
2179 skipws();
2180 if (_curchar != ';') {
2181 parse_err(SYNERR, "Missing ';' after constraint.\n");
2182 return NULL;
2183 }
2184 next_char();
2185
2186 // Create new "Constraint"
2187 Constraint *constraint = new Constraint(func,arg);
2188 return constraint;
2189 }
2190
2191 //------------------------------constr_parse-----------------------------------
construct_parse(void)2192 ConstructRule *ADLParser::construct_parse(void) {
2193 return NULL;
2194 }
2195
2196
2197 //------------------------------reg_def_parse----------------------------------
reg_def_parse(void)2198 void ADLParser::reg_def_parse(void) {
2199 char *rname; // Name of register being defined
2200
2201 // Get register name
2202 skipws(); // Skip whitespace
2203 rname = get_ident();
2204 if (rname == NULL) {
2205 parse_err(SYNERR, "missing register name after reg_def\n");
2206 return;
2207 }
2208
2209 // Check for definition of register calling convention (save on call, ...),
2210 // register save type, and register encoding value.
2211 skipws();
2212 char *callconv = NULL;
2213 char *c_conv = NULL;
2214 char *idealtype = NULL;
2215 char *encoding = NULL;
2216 char *concrete = NULL;
2217 if (_curchar == '(') {
2218 next_char();
2219 callconv = get_ident();
2220 // Parse the internal calling convention, must be NS, SOC, SOE, or AS.
2221 if (callconv == NULL) {
2222 parse_err(SYNERR, "missing register calling convention value\n");
2223 return;
2224 }
2225 if(strcmp(callconv, "SOC") && strcmp(callconv,"SOE") &&
2226 strcmp(callconv, "NS") && strcmp(callconv, "AS")) {
2227 parse_err(SYNERR, "invalid value for register calling convention\n");
2228 }
2229 skipws();
2230 if (_curchar != ',') {
2231 parse_err(SYNERR, "missing comma in register definition statement\n");
2232 return;
2233 }
2234 next_char();
2235
2236 // Parse the native calling convention, must be NS, SOC, SOE, AS
2237 c_conv = get_ident();
2238 if (c_conv == NULL) {
2239 parse_err(SYNERR, "missing register native calling convention value\n");
2240 return;
2241 }
2242 if(strcmp(c_conv, "SOC") && strcmp(c_conv,"SOE") &&
2243 strcmp(c_conv, "NS") && strcmp(c_conv, "AS")) {
2244 parse_err(SYNERR, "invalid value for register calling convention\n");
2245 }
2246 skipws();
2247 if (_curchar != ',') {
2248 parse_err(SYNERR, "missing comma in register definition statement\n");
2249 return;
2250 }
2251 next_char();
2252 skipws();
2253
2254 // Parse the ideal save type
2255 idealtype = get_ident();
2256 if (idealtype == NULL) {
2257 parse_err(SYNERR, "missing register save type value\n");
2258 return;
2259 }
2260 skipws();
2261 if (_curchar != ',') {
2262 parse_err(SYNERR, "missing comma in register definition statement\n");
2263 return;
2264 }
2265 next_char();
2266 skipws();
2267
2268 // Parse the encoding value
2269 encoding = get_expr("encoding", ",");
2270 if (encoding == NULL) {
2271 parse_err(SYNERR, "missing register encoding value\n");
2272 return;
2273 }
2274 trim(encoding);
2275 if (_curchar != ',') {
2276 parse_err(SYNERR, "missing comma in register definition statement\n");
2277 return;
2278 }
2279 next_char();
2280 skipws();
2281 // Parse the concrete name type
2282 // concrete = get_ident();
2283 concrete = get_expr("concrete", ")");
2284 if (concrete == NULL) {
2285 parse_err(SYNERR, "missing vm register name value\n");
2286 return;
2287 }
2288
2289 if (_curchar != ')') {
2290 parse_err(SYNERR, "missing ')' in register definition statement\n");
2291 return;
2292 }
2293 next_char();
2294 }
2295
2296 // Check for closing ';'
2297 skipws();
2298 if (_curchar != ';') {
2299 parse_err(SYNERR, "missing ';' after reg_def\n");
2300 return;
2301 }
2302 next_char(); // move past ';'
2303
2304 // Debug Stuff
2305 if (_AD._adl_debug > 1) {
2306 fprintf(stderr,"Register Definition: %s ( %s, %s %s )\n", rname,
2307 (callconv ? callconv : ""), (c_conv ? c_conv : ""), concrete);
2308 }
2309
2310 // Record new register definition.
2311 _AD._register->addRegDef(rname, callconv, c_conv, idealtype, encoding, concrete);
2312 return;
2313 }
2314
2315 //------------------------------reg_class_parse--------------------------------
reg_class_parse(void)2316 void ADLParser::reg_class_parse(void) {
2317 char *cname; // Name of register class being defined
2318
2319 // Get register class name
2320 skipws(); // Skip leading whitespace
2321 cname = get_ident();
2322 if (cname == NULL) {
2323 parse_err(SYNERR, "missing register class name after 'reg_class'\n");
2324 return;
2325 }
2326 // Debug Stuff
2327 if (_AD._adl_debug >1) fprintf(stderr,"Register Class: %s\n", cname);
2328
2329 skipws();
2330 if (_curchar == '(') {
2331 // A register list is defined for the register class.
2332 // Collect registers into a generic RegClass register class.
2333 RegClass* reg_class = _AD._register->addRegClass<RegClass>(cname);
2334
2335 next_char(); // Skip '('
2336 skipws();
2337 while (_curchar != ')') {
2338 char *rname = get_ident();
2339 if (rname==NULL) {
2340 parse_err(SYNERR, "missing identifier inside reg_class list.\n");
2341 return;
2342 }
2343 RegDef *regDef = _AD._register->getRegDef(rname);
2344 if (!regDef) {
2345 parse_err(SEMERR, "unknown identifier %s inside reg_class list.\n", rname);
2346 } else {
2347 reg_class->addReg(regDef); // add regDef to regClass
2348 }
2349
2350 // Check for ',' and position to next token.
2351 skipws();
2352 if (_curchar == ',') {
2353 next_char(); // Skip trailing ','
2354 skipws();
2355 }
2356 }
2357 next_char(); // Skip closing ')'
2358 } else if (_curchar == '%') {
2359 // A code snippet is defined for the register class.
2360 // Collect the code snippet into a CodeSnippetRegClass register class.
2361 CodeSnippetRegClass* reg_class = _AD._register->addRegClass<CodeSnippetRegClass>(cname);
2362 char *code = find_cpp_block("reg class");
2363 if (code == NULL) {
2364 parse_err(SYNERR, "missing code declaration for reg class.\n");
2365 return;
2366 }
2367 reg_class->set_code_snippet(code);
2368 return;
2369 }
2370
2371 // Check for terminating ';'
2372 skipws();
2373 if (_curchar != ';') {
2374 parse_err(SYNERR, "missing ';' at end of reg_class definition.\n");
2375 return;
2376 }
2377 next_char(); // Skip trailing ';'
2378
2379 // Check RegClass size, must be <= 32 registers in class.
2380
2381 return;
2382 }
2383
2384 //------------------------------reg_class_dynamic_parse------------------------
reg_class_dynamic_parse(void)2385 void ADLParser::reg_class_dynamic_parse(void) {
2386 char *cname; // Name of dynamic register class being defined
2387
2388 // Get register class name
2389 skipws();
2390 cname = get_ident();
2391 if (cname == NULL) {
2392 parse_err(SYNERR, "missing dynamic register class name after 'reg_class_dynamic'\n");
2393 return;
2394 }
2395
2396 if (_AD._adl_debug > 1) {
2397 fprintf(stdout, "Dynamic Register Class: %s\n", cname);
2398 }
2399
2400 skipws();
2401 if (_curchar != '(') {
2402 parse_err(SYNERR, "missing '(' at the beginning of reg_class_dynamic definition\n");
2403 return;
2404 }
2405 next_char();
2406 skipws();
2407
2408 // Collect two register classes and the C++ code representing the condition code used to
2409 // select between the two classes into a ConditionalRegClass register class.
2410 ConditionalRegClass* reg_class = _AD._register->addRegClass<ConditionalRegClass>(cname);
2411 int i;
2412 for (i = 0; i < 2; i++) {
2413 char* name = get_ident();
2414 if (name == NULL) {
2415 parse_err(SYNERR, "missing class identifier inside reg_class_dynamic list.\n");
2416 return;
2417 }
2418 RegClass* rc = _AD._register->getRegClass(name);
2419 if (rc == NULL) {
2420 parse_err(SEMERR, "unknown identifier %s inside reg_class_dynamic list.\n", name);
2421 } else {
2422 reg_class->set_rclass_at_index(i, rc);
2423 }
2424
2425 skipws();
2426 if (_curchar == ',') {
2427 next_char();
2428 skipws();
2429 } else {
2430 parse_err(SYNERR, "missing separator ',' inside reg_class_dynamic list.\n");
2431 }
2432 }
2433
2434 // Collect the condition code.
2435 skipws();
2436 if (_curchar == '%') {
2437 char* code = find_cpp_block("reg class dynamic");
2438 if (code == NULL) {
2439 parse_err(SYNERR, "missing code declaration for reg_class_dynamic.\n");
2440 return;
2441 }
2442 reg_class->set_condition_code(code);
2443 } else {
2444 parse_err(SYNERR, "missing %% at the beginning of code block in reg_class_dynamic definition\n");
2445 return;
2446 }
2447
2448 skipws();
2449 if (_curchar != ')') {
2450 parse_err(SYNERR, "missing ')' at the end of reg_class_dynamic definition\n");
2451 return;
2452 }
2453 next_char();
2454
2455 skipws();
2456 if (_curchar != ';') {
2457 parse_err(SYNERR, "missing ';' at the end of reg_class_dynamic definition.\n");
2458 return;
2459 }
2460 next_char(); // Skip trailing ';'
2461
2462 return;
2463 }
2464
2465 //------------------------------alloc_class_parse------------------------------
alloc_class_parse(void)2466 void ADLParser::alloc_class_parse(void) {
2467 char *name; // Name of allocation class being defined
2468
2469 // Get allocation class name
2470 skipws(); // Skip leading whitespace
2471 name = get_ident();
2472 if (name == NULL) {
2473 parse_err(SYNERR, "missing allocation class name after 'reg_class'\n");
2474 return;
2475 }
2476 // Debug Stuff
2477 if (_AD._adl_debug >1) fprintf(stderr,"Allocation Class: %s\n", name);
2478
2479 AllocClass *alloc_class = _AD._register->addAllocClass(name);
2480
2481 // Collect registers in class
2482 skipws();
2483 if (_curchar == '(') {
2484 next_char(); // Skip '('
2485 skipws();
2486 while (_curchar != ')') {
2487 char *rname = get_ident();
2488 if (rname==NULL) {
2489 parse_err(SYNERR, "missing identifier inside reg_class list.\n");
2490 return;
2491 }
2492 // Check if name is a RegDef
2493 RegDef *regDef = _AD._register->getRegDef(rname);
2494 if (regDef) {
2495 alloc_class->addReg(regDef); // add regDef to allocClass
2496 } else {
2497
2498 // name must be a RegDef or a RegClass
2499 parse_err(SYNERR, "name %s should be a previously defined reg_def.\n", rname);
2500 return;
2501 }
2502
2503 // Check for ',' and position to next token.
2504 skipws();
2505 if (_curchar == ',') {
2506 next_char(); // Skip trailing ','
2507 skipws();
2508 }
2509 }
2510 next_char(); // Skip closing ')'
2511 }
2512
2513 // Check for terminating ';'
2514 skipws();
2515 if (_curchar != ';') {
2516 parse_err(SYNERR, "missing ';' at end of reg_class definition.\n");
2517 return;
2518 }
2519 next_char(); // Skip trailing ';'
2520
2521 return;
2522 }
2523
2524 //------------------------------peep_match_child_parse-------------------------
peep_match_child_parse(PeepMatch & match,int parent,int & position,int input)2525 InstructForm *ADLParser::peep_match_child_parse(PeepMatch &match, int parent, int &position, int input){
2526 char *token = NULL;
2527 int lparen = 0; // keep track of parenthesis nesting depth
2528 int rparen = 0; // position of instruction at this depth
2529 InstructForm *inst_seen = NULL;
2530
2531 // Walk the match tree,
2532 // Record <parent, position, instruction name, input position>
2533 while ( lparen >= rparen ) {
2534 skipws();
2535 // Left paren signals start of an input, collect with recursive call
2536 if (_curchar == '(') {
2537 ++lparen;
2538 next_char();
2539 ( void ) peep_match_child_parse(match, parent, position, rparen);
2540 }
2541 // Right paren signals end of an input, may be more
2542 else if (_curchar == ')') {
2543 ++rparen;
2544 if( rparen == lparen ) { // IF rparen matches an lparen I've seen
2545 next_char(); // move past ')'
2546 } else { // ELSE leave ')' for parent
2547 assert( rparen == lparen + 1, "Should only see one extra ')'");
2548 // if an instruction was not specified for this paren-pair
2549 if( ! inst_seen ) { // record signal entry
2550 match.add_instruction( parent, position, NameList::_signal, input );
2551 ++position;
2552 }
2553 // ++input; // TEMPORARY
2554 return inst_seen;
2555 }
2556 }
2557 // if no parens, then check for instruction name
2558 // This instruction is the parent of a sub-tree
2559 else if ((token = get_ident_dup()) != NULL) {
2560 const Form *form = _AD._globalNames[token];
2561 if (form) {
2562 InstructForm *inst = form->is_instruction();
2563 // Record the first instruction at this level
2564 if( inst_seen == NULL ) {
2565 inst_seen = inst;
2566 }
2567 if (inst) {
2568 match.add_instruction( parent, position, token, input );
2569 parent = position;
2570 ++position;
2571 } else {
2572 parse_err(SYNERR, "instruction name expected at identifier %s.\n",
2573 token);
2574 return inst_seen;
2575 }
2576 }
2577 else {
2578 parse_err(SYNERR, "missing identifier in peepmatch rule.\n");
2579 return NULL;
2580 }
2581 }
2582 else {
2583 parse_err(SYNERR, "missing identifier in peepmatch rule.\n");
2584 return NULL;
2585 }
2586
2587 } // end while
2588
2589 assert( false, "ShouldNotReachHere();");
2590 return NULL;
2591 }
2592
2593 //------------------------------peep_match_parse-------------------------------
2594 // Syntax for a peepmatch rule
2595 //
2596 // peepmatch ( root_instr_name [(instruction subtree)] [,(instruction subtree)]* );
2597 //
peep_match_parse(Peephole & peep)2598 void ADLParser::peep_match_parse(Peephole &peep) {
2599
2600 skipws();
2601 // Check the structure of the rule
2602 // Check for open paren
2603 if (_curchar != '(') {
2604 parse_err(SYNERR, "missing '(' at start of peepmatch rule.\n");
2605 return;
2606 }
2607 next_char(); // skip '('
2608
2609 // Construct PeepMatch and parse the peepmatch rule.
2610 PeepMatch *match = new PeepMatch(_ptr);
2611 int parent = -1; // parent of root
2612 int position = 0; // zero-based positions
2613 int input = 0; // input position in parent's operands
2614 InstructForm *root= peep_match_child_parse( *match, parent, position, input);
2615 if( root == NULL ) {
2616 parse_err(SYNERR, "missing instruction-name at start of peepmatch.\n");
2617 return;
2618 }
2619
2620 if( _curchar != ')' ) {
2621 parse_err(SYNERR, "missing ')' at end of peepmatch.\n");
2622 return;
2623 }
2624 next_char(); // skip ')'
2625
2626 // Check for closing semicolon
2627 skipws();
2628 if( _curchar != ';' ) {
2629 parse_err(SYNERR, "missing ';' at end of peepmatch.\n");
2630 return;
2631 }
2632 next_char(); // skip ';'
2633
2634 // Store match into peep, and store peep into instruction
2635 peep.add_match(match);
2636 root->append_peephole(&peep);
2637 }
2638
2639 //------------------------------peep_constraint_parse--------------------------
2640 // Syntax for a peepconstraint rule
2641 // A parenthesized list of relations between operands in peepmatch subtree
2642 //
2643 // peepconstraint %{
2644 // (instruction_number.operand_name
2645 // relational_op
2646 // instruction_number.operand_name OR register_name
2647 // [, ...] );
2648 //
2649 // // instruction numbers are zero-based using topological order in peepmatch
2650 //
peep_constraint_parse(Peephole & peep)2651 void ADLParser::peep_constraint_parse(Peephole &peep) {
2652
2653 skipws();
2654 // Check the structure of the rule
2655 // Check for open paren
2656 if (_curchar != '(') {
2657 parse_err(SYNERR, "missing '(' at start of peepconstraint rule.\n");
2658 return;
2659 }
2660 else {
2661 next_char(); // Skip '('
2662 }
2663
2664 // Check for a constraint
2665 skipws();
2666 while( _curchar != ')' ) {
2667 // Get information on the left instruction and its operand
2668 // left-instructions's number
2669 int left_inst = get_int();
2670 // Left-instruction's operand
2671 skipws();
2672 if( _curchar != '.' ) {
2673 parse_err(SYNERR, "missing '.' in peepconstraint after instruction number.\n");
2674 return;
2675 }
2676 next_char(); // Skip '.'
2677 char *left_op = get_ident_dup();
2678
2679 skipws();
2680 // Collect relational operator
2681 char *relation = get_relation_dup();
2682
2683 skipws();
2684 // Get information on the right instruction and its operand
2685 int right_inst; // Right-instructions's number
2686 if( isdigit(_curchar) ) {
2687 right_inst = get_int();
2688 // Right-instruction's operand
2689 skipws();
2690 if( _curchar != '.' ) {
2691 parse_err(SYNERR, "missing '.' in peepconstraint after instruction number.\n");
2692 return;
2693 }
2694 next_char(); // Skip '.'
2695 } else {
2696 right_inst = -1; // Flag as being a register constraint
2697 }
2698
2699 char *right_op = get_ident_dup();
2700
2701 // Construct the next PeepConstraint
2702 PeepConstraint *constraint = new PeepConstraint( left_inst, left_op,
2703 relation,
2704 right_inst, right_op );
2705 // And append it to the list for this peephole rule
2706 peep.append_constraint( constraint );
2707
2708 // Check for another constraint, or end of rule
2709 skipws();
2710 if( _curchar == ',' ) {
2711 next_char(); // Skip ','
2712 skipws();
2713 }
2714 else if( _curchar != ')' ) {
2715 parse_err(SYNERR, "expected ',' or ')' after peephole constraint.\n");
2716 return;
2717 }
2718 } // end while( processing constraints )
2719 next_char(); // Skip ')'
2720
2721 // Check for terminating ';'
2722 skipws();
2723 if (_curchar != ';') {
2724 parse_err(SYNERR, "missing ';' at end of peepconstraint.\n");
2725 return;
2726 }
2727 next_char(); // Skip trailing ';'
2728 }
2729
2730
2731 //------------------------------peep_replace_parse-----------------------------
2732 // Syntax for a peepreplace rule
2733 // root instruction name followed by a
2734 // parenthesized list of whitespace separated instruction.operand specifiers
2735 //
2736 // peepreplace ( instr_name ( [instruction_number.operand_name]* ) );
2737 //
2738 //
peep_replace_parse(Peephole & peep)2739 void ADLParser::peep_replace_parse(Peephole &peep) {
2740 int lparen = 0; // keep track of parenthesis nesting depth
2741 int rparen = 0; // keep track of parenthesis nesting depth
2742 int icount = 0; // count of instructions in rule for naming
2743 char *str = NULL;
2744 char *token = NULL;
2745
2746 skipws();
2747 // Check for open paren
2748 if (_curchar != '(') {
2749 parse_err(SYNERR, "missing '(' at start of peepreplace rule.\n");
2750 return;
2751 }
2752 else {
2753 lparen++;
2754 next_char();
2755 }
2756
2757 // Check for root instruction
2758 char *inst = get_ident_dup();
2759 const Form *form = _AD._globalNames[inst];
2760 if( form == NULL || form->is_instruction() == NULL ) {
2761 parse_err(SYNERR, "Instruction name expected at start of peepreplace.\n");
2762 return;
2763 }
2764
2765 // Store string representation of rule into replace
2766 PeepReplace *replace = new PeepReplace(str);
2767 replace->add_instruction( inst );
2768
2769 skipws();
2770 // Start of root's operand-list
2771 if (_curchar != '(') {
2772 parse_err(SYNERR, "missing '(' at peepreplace root's operand-list.\n");
2773 return;
2774 }
2775 else {
2776 lparen++;
2777 next_char();
2778 }
2779
2780 skipws();
2781 // Get the list of operands
2782 while( _curchar != ')' ) {
2783 // Get information on an instruction and its operand
2784 // instructions's number
2785 int inst_num = get_int();
2786 // Left-instruction's operand
2787 skipws();
2788 if( _curchar != '.' ) {
2789 parse_err(SYNERR, "missing '.' in peepreplace after instruction number.\n");
2790 return;
2791 }
2792 next_char(); // Skip '.'
2793 char *inst_op = get_ident_dup();
2794 if( inst_op == NULL ) {
2795 parse_err(SYNERR, "missing operand identifier in peepreplace.\n");
2796 return;
2797 }
2798
2799 // Record this operand's position in peepmatch
2800 replace->add_operand( inst_num, inst_op );
2801 skipws();
2802 }
2803
2804 // Check for the end of operands list
2805 skipws();
2806 assert( _curchar == ')', "While loop should have advanced to ')'.");
2807 next_char(); // Skip ')'
2808
2809 skipws();
2810 // Check for end of peepreplace
2811 if( _curchar != ')' ) {
2812 parse_err(SYNERR, "missing ')' at end of peepmatch.\n");
2813 parse_err(SYNERR, "Support one replacement instruction.\n");
2814 return;
2815 }
2816 next_char(); // Skip ')'
2817
2818 // Check for closing semicolon
2819 skipws();
2820 if( _curchar != ';' ) {
2821 parse_err(SYNERR, "missing ';' at end of peepreplace.\n");
2822 return;
2823 }
2824 next_char(); // skip ';'
2825
2826 // Store replace into peep
2827 peep.add_replace( replace );
2828 }
2829
2830 //------------------------------pred_parse-------------------------------------
pred_parse(void)2831 Predicate *ADLParser::pred_parse(void) {
2832 Predicate *predicate; // Predicate class for operand
2833 char *rule = NULL; // String representation of predicate
2834
2835 skipws(); // Skip leading whitespace
2836 int line = linenum();
2837 if ( (rule = get_paren_expr("pred expression", true)) == NULL ) {
2838 parse_err(SYNERR, "incorrect or missing expression for 'predicate'\n");
2839 return NULL;
2840 }
2841 // Debug Stuff
2842 if (_AD._adl_debug > 1) fprintf(stderr,"Predicate: %s\n", rule);
2843 if (_curchar != ';') {
2844 parse_err(SYNERR, "missing ';' in predicate definition\n");
2845 return NULL;
2846 }
2847 next_char(); // Point after the terminator
2848
2849 predicate = new Predicate(rule); // Build new predicate object
2850 skipws();
2851 return predicate;
2852 }
2853
2854
2855 //------------------------------ins_encode_parse_block-------------------------
2856 // Parse the block form of ins_encode. See ins_encode_parse for more details
ins_encode_parse_block(InstructForm & inst)2857 void ADLParser::ins_encode_parse_block(InstructForm& inst) {
2858 // Create a new encoding name based on the name of the instruction
2859 // definition, which should be unique.
2860 const char* prefix = "__ins_encode_";
2861 char* ec_name = (char*) malloc(strlen(inst._ident) + strlen(prefix) + 1);
2862 sprintf(ec_name, "%s%s", prefix, inst._ident);
2863
2864 assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist");
2865 EncClass* encoding = _AD._encode->add_EncClass(ec_name);
2866 encoding->_linenum = linenum();
2867
2868 // synthesize the arguments list for the enc_class from the
2869 // arguments to the instruct definition.
2870 const char* param = NULL;
2871 inst._parameters.reset();
2872 while ((param = inst._parameters.iter()) != NULL) {
2873 OpClassForm* opForm = inst._localNames[param]->is_opclass();
2874 assert(opForm != NULL, "sanity");
2875 encoding->add_parameter(opForm->_ident, param);
2876 }
2877
2878 if (!inst._is_postalloc_expand) {
2879 // Define a MacroAssembler instance for use by the encoding. The
2880 // name is chosen to match the __ idiom used for assembly in other
2881 // parts of hotspot and assumes the existence of the standard
2882 // #define __ _masm.
2883 encoding->add_code(" MacroAssembler _masm(&cbuf);\n");
2884 }
2885
2886 // Parse the following %{ }% block
2887 ins_encode_parse_block_impl(inst, encoding, ec_name);
2888
2889 // Build an encoding rule which invokes the encoding rule we just
2890 // created, passing all arguments that we received.
2891 InsEncode* encrule = new InsEncode(); // Encode class for instruction
2892 NameAndList* params = encrule->add_encode(ec_name);
2893 inst._parameters.reset();
2894 while ((param = inst._parameters.iter()) != NULL) {
2895 params->add_entry(param);
2896 }
2897
2898 // Check for duplicate ins_encode sections after parsing the block
2899 // so that parsing can continue and find any other errors.
2900 if (inst._insencode != NULL) {
2901 parse_err(SYNERR, "Multiple ins_encode sections defined\n");
2902 return;
2903 }
2904
2905 // Set encode class of this instruction.
2906 inst._insencode = encrule;
2907 }
2908
2909
ins_encode_parse_block_impl(InstructForm & inst,EncClass * encoding,char * ec_name)2910 void ADLParser::ins_encode_parse_block_impl(InstructForm& inst, EncClass* encoding, char* ec_name) {
2911 skipws_no_preproc(); // Skip leading whitespace
2912 // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block
2913 if (_AD._adlocation_debug) {
2914 encoding->add_code(get_line_string());
2915 }
2916
2917 // Collect the parts of the encode description
2918 // (1) strings that are passed through to output
2919 // (2) replacement/substitution variable, preceeded by a '$'
2920 while ((_curchar != '%') && (*(_ptr+1) != '}')) {
2921
2922 // (1)
2923 // Check if there is a string to pass through to output
2924 char *start = _ptr; // Record start of the next string
2925 while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {
2926 // If at the start of a comment, skip past it
2927 if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {
2928 skipws_no_preproc();
2929 } else {
2930 // ELSE advance to the next character, or start of the next line
2931 next_char_or_line();
2932 }
2933 }
2934 // If a string was found, terminate it and record in EncClass
2935 if (start != _ptr) {
2936 *_ptr = '\0'; // Terminate the string
2937 encoding->add_code(start);
2938 }
2939
2940 // (2)
2941 // If we are at a replacement variable,
2942 // copy it and record in EncClass
2943 if (_curchar == '$') {
2944 // Found replacement Variable
2945 char* rep_var = get_rep_var_ident_dup();
2946
2947 // Add flag to _strings list indicating we should check _rep_vars
2948 encoding->add_rep_var(rep_var);
2949
2950 skipws();
2951
2952 // Check if this instruct is a MachConstantNode.
2953 if (strcmp(rep_var, "constanttablebase") == 0) {
2954 // This instruct is a MachConstantNode.
2955 inst.set_needs_constant_base(true);
2956 if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) {
2957 inst.set_is_mach_constant(true);
2958 }
2959
2960 if (_curchar == '(') {
2961 parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument "
2962 "(only constantaddress and constantoffset)", ec_name);
2963 return;
2964 }
2965 }
2966 else if ((strcmp(rep_var, "constantaddress") == 0) ||
2967 (strcmp(rep_var, "constantoffset") == 0)) {
2968 // This instruct is a MachConstantNode.
2969 inst.set_is_mach_constant(true);
2970
2971 // If the constant keyword has an argument, parse it.
2972 if (_curchar == '(') constant_parse(inst);
2973 }
2974 }
2975 } // end while part of format description
2976 next_char(); // Skip '%'
2977 next_char(); // Skip '}'
2978
2979 skipws();
2980
2981 if (_AD._adlocation_debug) {
2982 encoding->add_code(end_line_marker());
2983 }
2984
2985 // Debug Stuff
2986 if (_AD._adl_debug > 1) fprintf(stderr, "EncodingClass Form: %s\n", ec_name);
2987 }
2988
2989
2990 //------------------------------ins_encode_parse-------------------------------
2991 // Encode rules have the form
2992 // ins_encode( encode_class_name(parameter_list), ... );
2993 //
2994 // The "encode_class_name" must be defined in the encode section
2995 // The parameter list contains $names that are locals.
2996 //
2997 // Alternatively it can be written like this:
2998 //
2999 // ins_encode %{
3000 // ... // body
3001 // %}
3002 //
3003 // which synthesizes a new encoding class taking the same arguments as
3004 // the InstructForm, and automatically prefixes the definition with:
3005 //
3006 // MacroAssembler masm(&cbuf);\n");
3007 //
3008 // making it more compact to take advantage of the MacroAssembler and
3009 // placing the assembly closer to it's use by instructions.
ins_encode_parse(InstructForm & inst)3010 void ADLParser::ins_encode_parse(InstructForm& inst) {
3011
3012 // Parse encode class name
3013 skipws(); // Skip whitespace
3014 if (_curchar != '(') {
3015 // Check for ins_encode %{ form
3016 if ((_curchar == '%') && (*(_ptr+1) == '{')) {
3017 next_char(); // Skip '%'
3018 next_char(); // Skip '{'
3019
3020 // Parse the block form of ins_encode
3021 ins_encode_parse_block(inst);
3022 return;
3023 }
3024
3025 parse_err(SYNERR, "missing '%%{' or '(' in ins_encode definition\n");
3026 return;
3027 }
3028 next_char(); // move past '('
3029 skipws();
3030
3031 InsEncode *encrule = new InsEncode(); // Encode class for instruction
3032 encrule->_linenum = linenum();
3033 char *ec_name = NULL; // String representation of encode rule
3034 // identifier is optional.
3035 while (_curchar != ')') {
3036 ec_name = get_ident();
3037 if (ec_name == NULL) {
3038 parse_err(SYNERR, "Invalid encode class name after 'ins_encode('.\n");
3039 return;
3040 }
3041 // Check that encoding is defined in the encode section
3042 EncClass *encode_class = _AD._encode->encClass(ec_name);
3043 if (encode_class == NULL) {
3044 // Like to defer checking these till later...
3045 // parse_err(WARN, "Using an undefined encode class '%s' in 'ins_encode'.\n", ec_name);
3046 }
3047
3048 // Get list for encode method's parameters
3049 NameAndList *params = encrule->add_encode(ec_name);
3050
3051 // Parse the parameters to this encode method.
3052 skipws();
3053 if ( _curchar == '(' ) {
3054 next_char(); // move past '(' for parameters
3055
3056 // Parse the encode method's parameters
3057 while (_curchar != ')') {
3058 char *param = get_ident_or_literal_constant("encoding operand");
3059 if ( param != NULL ) {
3060
3061 // Check if this instruct is a MachConstantNode.
3062 if (strcmp(param, "constanttablebase") == 0) {
3063 // This instruct is a MachConstantNode.
3064 inst.set_needs_constant_base(true);
3065 if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) {
3066 inst.set_is_mach_constant(true);
3067 }
3068
3069 if (_curchar == '(') {
3070 parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument "
3071 "(only constantaddress and constantoffset)", ec_name);
3072 return;
3073 }
3074 } else {
3075 // Found a parameter:
3076 // Check it is a local name, add it to the list, then check for more
3077 // New: allow hex constants as parameters to an encode method.
3078 // New: allow parenthesized expressions as parameters.
3079 // New: allow "primary", "secondary", "tertiary" as parameters.
3080 // New: allow user-defined register name as parameter
3081 if ( (inst._localNames[param] == NULL) &&
3082 !ADLParser::is_literal_constant(param) &&
3083 (Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&
3084 ((_AD._register == NULL ) || (_AD._register->getRegDef(param) == NULL)) ) {
3085 parse_err(SYNERR, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name);
3086 return;
3087 }
3088 }
3089 params->add_entry(param);
3090
3091 skipws();
3092 if (_curchar == ',' ) {
3093 // More parameters to come
3094 next_char(); // move past ',' between parameters
3095 skipws(); // Skip to next parameter
3096 }
3097 else if (_curchar == ')') {
3098 // Done with parameter list
3099 }
3100 else {
3101 // Only ',' or ')' are valid after a parameter name
3102 parse_err(SYNERR, "expected ',' or ')' after parameter %s.\n",
3103 ec_name);
3104 return;
3105 }
3106
3107 } else {
3108 skipws();
3109 // Did not find a parameter
3110 if (_curchar == ',') {
3111 parse_err(SYNERR, "Expected encode parameter before ',' in encoding %s.\n", ec_name);
3112 return;
3113 }
3114 if (_curchar != ')') {
3115 parse_err(SYNERR, "Expected ')' after encode parameters.\n");
3116 return;
3117 }
3118 }
3119 } // WHILE loop collecting parameters
3120 next_char(); // move past ')' at end of parameters
3121 } // done with parameter list for encoding
3122
3123 // Check for ',' or ')' after encoding
3124 skipws(); // move to character after parameters
3125 if ( _curchar == ',' ) {
3126 // Found a ','
3127 next_char(); // move past ',' between encode methods
3128 skipws();
3129 }
3130 else if ( _curchar != ')' ) {
3131 // If not a ',' then only a ')' is allowed
3132 parse_err(SYNERR, "Expected ')' after encoding %s.\n", ec_name);
3133 return;
3134 }
3135
3136 // Check for ',' separating parameters
3137 // if ( _curchar != ',' && _curchar != ')' ) {
3138 // parse_err(SYNERR, "expected ',' or ')' after encode method inside ins_encode.\n");
3139 // return NULL;
3140 // }
3141
3142 } // done parsing ins_encode methods and their parameters
3143 if (_curchar != ')') {
3144 parse_err(SYNERR, "Missing ')' at end of ins_encode description.\n");
3145 return;
3146 }
3147 next_char(); // move past ')'
3148 skipws(); // Skip leading whitespace
3149
3150 if ( _curchar != ';' ) {
3151 parse_err(SYNERR, "Missing ';' at end of ins_encode.\n");
3152 return;
3153 }
3154 next_char(); // move past ';'
3155 skipws(); // be friendly to oper_parse()
3156
3157 // Check for duplicate ins_encode sections after parsing the block
3158 // so that parsing can continue and find any other errors.
3159 if (inst._insencode != NULL) {
3160 parse_err(SYNERR, "Multiple ins_encode sections defined\n");
3161 return;
3162 }
3163
3164 // Debug Stuff
3165 if (_AD._adl_debug > 1) fprintf(stderr,"Instruction Encode: %s\n", ec_name);
3166
3167 // Set encode class of this instruction.
3168 inst._insencode = encrule;
3169 }
3170
3171 //------------------------------postalloc_expand_parse---------------------------
3172 // Encode rules have the form
3173 // postalloc_expand( encode_class_name(parameter_list) );
3174 //
3175 // The "encode_class_name" must be defined in the encode section.
3176 // The parameter list contains $names that are locals.
3177 //
3178 // This is just a copy of ins_encode_parse without the loop.
postalloc_expand_parse(InstructForm & inst)3179 void ADLParser::postalloc_expand_parse(InstructForm& inst) {
3180 inst._is_postalloc_expand = true;
3181
3182 // Parse encode class name.
3183 skipws(); // Skip whitespace.
3184 if (_curchar != '(') {
3185 // Check for postalloc_expand %{ form
3186 if ((_curchar == '%') && (*(_ptr+1) == '{')) {
3187 next_char(); // Skip '%'
3188 next_char(); // Skip '{'
3189
3190 // Parse the block form of postalloc_expand
3191 ins_encode_parse_block(inst);
3192 return;
3193 }
3194
3195 parse_err(SYNERR, "missing '(' in postalloc_expand definition\n");
3196 return;
3197 }
3198 next_char(); // Move past '('.
3199 skipws();
3200
3201 InsEncode *encrule = new InsEncode(); // Encode class for instruction.
3202 encrule->_linenum = linenum();
3203 char *ec_name = NULL; // String representation of encode rule.
3204 // identifier is optional.
3205 if (_curchar != ')') {
3206 ec_name = get_ident();
3207 if (ec_name == NULL) {
3208 parse_err(SYNERR, "Invalid postalloc_expand class name after 'postalloc_expand('.\n");
3209 return;
3210 }
3211 // Check that encoding is defined in the encode section.
3212 EncClass *encode_class = _AD._encode->encClass(ec_name);
3213
3214 // Get list for encode method's parameters
3215 NameAndList *params = encrule->add_encode(ec_name);
3216
3217 // Parse the parameters to this encode method.
3218 skipws();
3219 if (_curchar == '(') {
3220 next_char(); // Move past '(' for parameters.
3221
3222 // Parse the encode method's parameters.
3223 while (_curchar != ')') {
3224 char *param = get_ident_or_literal_constant("encoding operand");
3225 if (param != NULL) {
3226 // Found a parameter:
3227
3228 // First check for constant table support.
3229
3230 // Check if this instruct is a MachConstantNode.
3231 if (strcmp(param, "constanttablebase") == 0) {
3232 // This instruct is a MachConstantNode.
3233 inst.set_needs_constant_base(true);
3234 if (strncmp("MachCall", inst.mach_base_class(_globalNames), strlen("MachCall")) != 0 ) {
3235 inst.set_is_mach_constant(true);
3236 }
3237
3238 if (_curchar == '(') {
3239 parse_err(SYNERR, "constanttablebase in instruct %s cannot have an argument "
3240 "(only constantaddress and constantoffset)", ec_name);
3241 return;
3242 }
3243 }
3244 else if ((strcmp(param, "constantaddress") == 0) ||
3245 (strcmp(param, "constantoffset") == 0)) {
3246 // This instruct is a MachConstantNode.
3247 inst.set_is_mach_constant(true);
3248
3249 // If the constant keyword has an argument, parse it.
3250 if (_curchar == '(') constant_parse(inst);
3251 }
3252
3253 // Else check it is a local name, add it to the list, then check for more.
3254 // New: allow hex constants as parameters to an encode method.
3255 // New: allow parenthesized expressions as parameters.
3256 // New: allow "primary", "secondary", "tertiary" as parameters.
3257 // New: allow user-defined register name as parameter.
3258 else if ((inst._localNames[param] == NULL) &&
3259 !ADLParser::is_literal_constant(param) &&
3260 (Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&
3261 ((_AD._register == NULL) || (_AD._register->getRegDef(param) == NULL))) {
3262 parse_err(SYNERR, "Using non-locally defined parameter %s for encoding %s.\n", param, ec_name);
3263 return;
3264 }
3265 params->add_entry(param);
3266
3267 skipws();
3268 if (_curchar == ',') {
3269 // More parameters to come.
3270 next_char(); // Move past ',' between parameters.
3271 skipws(); // Skip to next parameter.
3272 } else if (_curchar == ')') {
3273 // Done with parameter list
3274 } else {
3275 // Only ',' or ')' are valid after a parameter name.
3276 parse_err(SYNERR, "expected ',' or ')' after parameter %s.\n", ec_name);
3277 return;
3278 }
3279
3280 } else {
3281 skipws();
3282 // Did not find a parameter.
3283 if (_curchar == ',') {
3284 parse_err(SYNERR, "Expected encode parameter before ',' in postalloc_expand %s.\n", ec_name);
3285 return;
3286 }
3287 if (_curchar != ')') {
3288 parse_err(SYNERR, "Expected ')' after postalloc_expand parameters.\n");
3289 return;
3290 }
3291 }
3292 } // WHILE loop collecting parameters.
3293 next_char(); // Move past ')' at end of parameters.
3294 } // Done with parameter list for encoding.
3295
3296 // Check for ',' or ')' after encoding.
3297 skipws(); // Move to character after parameters.
3298 if (_curchar != ')') {
3299 // Only a ')' is allowed.
3300 parse_err(SYNERR, "Expected ')' after postalloc_expand %s.\n", ec_name);
3301 return;
3302 }
3303 } // Done parsing postalloc_expand method and their parameters.
3304 if (_curchar != ')') {
3305 parse_err(SYNERR, "Missing ')' at end of postalloc_expand description.\n");
3306 return;
3307 }
3308 next_char(); // Move past ')'.
3309 skipws(); // Skip leading whitespace.
3310
3311 if (_curchar != ';') {
3312 parse_err(SYNERR, "Missing ';' at end of postalloc_expand.\n");
3313 return;
3314 }
3315 next_char(); // Move past ';'.
3316 skipws(); // Be friendly to oper_parse().
3317
3318 // Debug Stuff.
3319 if (_AD._adl_debug > 1) fprintf(stderr, "Instruction postalloc_expand: %s\n", ec_name);
3320
3321 // Set encode class of this instruction.
3322 inst._insencode = encrule;
3323 }
3324
3325
3326 //------------------------------constant_parse---------------------------------
3327 // Parse a constant expression.
constant_parse(InstructForm & inst)3328 void ADLParser::constant_parse(InstructForm& inst) {
3329 // Create a new encoding name based on the name of the instruction
3330 // definition, which should be unique.
3331 const char* prefix = "__constant_";
3332 char* ec_name = (char*) malloc(strlen(inst._ident) + strlen(prefix) + 1);
3333 sprintf(ec_name, "%s%s", prefix, inst._ident);
3334
3335 assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist");
3336 EncClass* encoding = _AD._encode->add_EncClass(ec_name);
3337 encoding->_linenum = linenum();
3338
3339 // synthesize the arguments list for the enc_class from the
3340 // arguments to the instruct definition.
3341 const char* param = NULL;
3342 inst._parameters.reset();
3343 while ((param = inst._parameters.iter()) != NULL) {
3344 OpClassForm* opForm = inst._localNames[param]->is_opclass();
3345 assert(opForm != NULL, "sanity");
3346 encoding->add_parameter(opForm->_ident, param);
3347 }
3348
3349 // Parse the following ( ) expression.
3350 constant_parse_expression(encoding, ec_name);
3351
3352 // Build an encoding rule which invokes the encoding rule we just
3353 // created, passing all arguments that we received.
3354 InsEncode* encrule = new InsEncode(); // Encode class for instruction
3355 NameAndList* params = encrule->add_encode(ec_name);
3356 inst._parameters.reset();
3357 while ((param = inst._parameters.iter()) != NULL) {
3358 params->add_entry(param);
3359 }
3360
3361 // Set encode class of this instruction.
3362 inst._constant = encrule;
3363 }
3364
3365
3366 //------------------------------constant_parse_expression----------------------
constant_parse_expression(EncClass * encoding,char * ec_name)3367 void ADLParser::constant_parse_expression(EncClass* encoding, char* ec_name) {
3368 skipws();
3369
3370 // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block
3371 if (_AD._adlocation_debug) {
3372 encoding->add_code(get_line_string());
3373 }
3374
3375 // Start code line.
3376 encoding->add_code(" _constant = C->constant_table().add");
3377
3378 // Parse everything in ( ) expression.
3379 encoding->add_code("(this, ");
3380 next_char(); // Skip '('
3381 int parens_depth = 1;
3382
3383 // Collect the parts of the constant expression.
3384 // (1) strings that are passed through to output
3385 // (2) replacement/substitution variable, preceeded by a '$'
3386 while (parens_depth > 0) {
3387 if (_curchar == '(') {
3388 parens_depth++;
3389 encoding->add_code("(");
3390 next_char();
3391 }
3392 else if (_curchar == ')') {
3393 parens_depth--;
3394 if (parens_depth > 0)
3395 encoding->add_code(")");
3396 next_char();
3397 }
3398 else {
3399 // (1)
3400 // Check if there is a string to pass through to output
3401 char *start = _ptr; // Record start of the next string
3402 while ((_curchar != '$') && (_curchar != '(') && (_curchar != ')')) {
3403 next_char();
3404 }
3405 // If a string was found, terminate it and record in EncClass
3406 if (start != _ptr) {
3407 *_ptr = '\0'; // Terminate the string
3408 encoding->add_code(start);
3409 }
3410
3411 // (2)
3412 // If we are at a replacement variable, copy it and record in EncClass.
3413 if (_curchar == '$') {
3414 // Found replacement Variable
3415 char* rep_var = get_rep_var_ident_dup();
3416 encoding->add_rep_var(rep_var);
3417 }
3418 }
3419 }
3420
3421 // Finish code line.
3422 encoding->add_code(");");
3423
3424 if (_AD._adlocation_debug) {
3425 encoding->add_code(end_line_marker());
3426 }
3427
3428 // Debug Stuff
3429 if (_AD._adl_debug > 1) fprintf(stderr, "EncodingClass Form: %s\n", ec_name);
3430 }
3431
3432
3433 //------------------------------size_parse-----------------------------------
3434 // Parse a 'size(<expr>)' attribute which specifies the size of the
3435 // emitted instructions in bytes. <expr> can be a C++ expression,
3436 // e.g. a constant.
size_parse(InstructForm * instr)3437 char* ADLParser::size_parse(InstructForm *instr) {
3438 char* sizeOfInstr = NULL;
3439
3440 // Get value of the instruction's size
3441 skipws();
3442
3443 // Parse size
3444 sizeOfInstr = get_paren_expr("size expression");
3445 if (sizeOfInstr == NULL) {
3446 parse_err(SYNERR, "size of opcode expected at %c\n", _curchar);
3447 return NULL;
3448 }
3449
3450 skipws();
3451
3452 // Check for terminator
3453 if (_curchar != ';') {
3454 parse_err(SYNERR, "missing ';' in ins_attrib definition\n");
3455 return NULL;
3456 }
3457 next_char(); // Advance past the ';'
3458 skipws(); // necessary for instr_parse()
3459
3460 // Debug Stuff
3461 if (_AD._adl_debug > 1) {
3462 if (sizeOfInstr != NULL) {
3463 fprintf(stderr,"size of opcode: %s\n", sizeOfInstr);
3464 }
3465 }
3466
3467 return sizeOfInstr;
3468 }
3469
3470
3471 //------------------------------opcode_parse-----------------------------------
opcode_parse(InstructForm * instr)3472 Opcode * ADLParser::opcode_parse(InstructForm *instr) {
3473 char *primary = NULL;
3474 char *secondary = NULL;
3475 char *tertiary = NULL;
3476
3477 char *val = NULL;
3478 Opcode *opcode = NULL;
3479
3480 // Get value of the instruction's opcode
3481 skipws();
3482 if (_curchar != '(') { // Check for parenthesized operand list
3483 parse_err(SYNERR, "missing '(' in expand instruction declaration\n");
3484 return NULL;
3485 }
3486 next_char(); // skip open paren
3487 skipws();
3488 if (_curchar != ')') {
3489 // Parse primary, secondary, and tertiary opcodes, if provided.
3490 if ( (primary = get_ident_or_literal_constant("primary opcode")) == NULL ) {
3491 parse_err(SYNERR, "primary hex opcode expected at %c\n", _curchar);
3492 return NULL;
3493 }
3494 skipws();
3495 if (_curchar == ',') {
3496 next_char();
3497 skipws();
3498 // Parse secondary opcode
3499 if ( (secondary = get_ident_or_literal_constant("secondary opcode")) == NULL ) {
3500 parse_err(SYNERR, "secondary hex opcode expected at %c\n", _curchar);
3501 return NULL;
3502 }
3503 skipws();
3504 if (_curchar == ',') {
3505 next_char();
3506 skipws();
3507 // Parse tertiary opcode
3508 if ( (tertiary = get_ident_or_literal_constant("tertiary opcode")) == NULL ) {
3509 parse_err(SYNERR,"tertiary hex opcode expected at %c\n", _curchar);
3510 return NULL;
3511 }
3512 skipws();
3513 }
3514 }
3515 skipws();
3516 if (_curchar != ')') {
3517 parse_err(SYNERR, "Missing ')' in opcode description\n");
3518 return NULL;
3519 }
3520 }
3521 next_char(); // Skip ')'
3522 skipws();
3523 // Check for terminator
3524 if (_curchar != ';') {
3525 parse_err(SYNERR, "missing ';' in ins_attrib definition\n");
3526 return NULL;
3527 }
3528 next_char(); // Advance past the ';'
3529 skipws(); // necessary for instr_parse()
3530
3531 // Debug Stuff
3532 if (_AD._adl_debug > 1) {
3533 if (primary != NULL) fprintf(stderr,"primary opcode: %s\n", primary);
3534 if (secondary != NULL) fprintf(stderr,"secondary opcode: %s\n", secondary);
3535 if (tertiary != NULL) fprintf(stderr,"tertiary opcode: %s\n", tertiary);
3536 }
3537
3538 // Generate new object and return
3539 opcode = new Opcode(primary, secondary, tertiary);
3540 return opcode;
3541 }
3542
3543
3544 //------------------------------interface_parse--------------------------------
interface_parse(void)3545 Interface *ADLParser::interface_parse(void) {
3546 char *iface_name = NULL; // Name of interface class being used
3547 char *iface_code = NULL; // Describe components of this class
3548
3549 // Get interface class name
3550 skipws(); // Skip whitespace
3551 if (_curchar != '(') {
3552 parse_err(SYNERR, "Missing '(' at start of interface description.\n");
3553 return NULL;
3554 }
3555 next_char(); // move past '('
3556 skipws();
3557 iface_name = get_ident();
3558 if (iface_name == NULL) {
3559 parse_err(SYNERR, "missing interface name after 'interface'.\n");
3560 return NULL;
3561 }
3562 skipws();
3563 if (_curchar != ')') {
3564 parse_err(SYNERR, "Missing ')' after name of interface.\n");
3565 return NULL;
3566 }
3567 next_char(); // move past ')'
3568
3569 // Get details of the interface,
3570 // for the type of interface indicated by iface_name.
3571 Interface *inter = NULL;
3572 skipws();
3573 if ( _curchar != ';' ) {
3574 if ( strcmp(iface_name,"MEMORY_INTER") == 0 ) {
3575 inter = mem_interface_parse();
3576 }
3577 else if ( strcmp(iface_name,"COND_INTER") == 0 ) {
3578 inter = cond_interface_parse();
3579 }
3580 // The parse routines consume the "%}"
3581
3582 // Check for probable extra ';' after defining block.
3583 if ( _curchar == ';' ) {
3584 parse_err(SYNERR, "Extra ';' after defining interface block.\n");
3585 next_char(); // Skip ';'
3586 return NULL;
3587 }
3588 } else {
3589 next_char(); // move past ';'
3590
3591 // Create appropriate interface object
3592 if ( strcmp(iface_name,"REG_INTER") == 0 ) {
3593 inter = new RegInterface();
3594 }
3595 else if ( strcmp(iface_name,"CONST_INTER") == 0 ) {
3596 inter = new ConstInterface();
3597 }
3598 }
3599 skipws(); // be friendly to oper_parse()
3600 // Debug Stuff
3601 if (_AD._adl_debug > 1) fprintf(stderr,"Interface Form: %s\n", iface_name);
3602
3603 // Create appropriate interface object and return.
3604 return inter;
3605 }
3606
3607
3608 //------------------------------mem_interface_parse----------------------------
mem_interface_parse(void)3609 Interface *ADLParser::mem_interface_parse(void) {
3610 // Fields for MemInterface
3611 char *base = NULL;
3612 char *index = NULL;
3613 char *scale = NULL;
3614 char *disp = NULL;
3615
3616 if (_curchar != '%') {
3617 parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n");
3618 return NULL;
3619 }
3620 next_char(); // Skip '%'
3621 if (_curchar != '{') {
3622 parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n");
3623 return NULL;
3624 }
3625 next_char(); // Skip '{'
3626 skipws();
3627 do {
3628 char *field = get_ident();
3629 if (field == NULL) {
3630 parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
3631 return NULL;
3632 }
3633 if ( strcmp(field,"base") == 0 ) {
3634 base = interface_field_parse();
3635 }
3636 else if ( strcmp(field,"index") == 0 ) {
3637 index = interface_field_parse();
3638 }
3639 else if ( strcmp(field,"scale") == 0 ) {
3640 scale = interface_field_parse();
3641 }
3642 else if ( strcmp(field,"disp") == 0 ) {
3643 disp = interface_field_parse();
3644 }
3645 else {
3646 parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
3647 return NULL;
3648 }
3649 } while( _curchar != '%' );
3650 next_char(); // Skip '%'
3651 if ( _curchar != '}' ) {
3652 parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n");
3653 return NULL;
3654 }
3655 next_char(); // Skip '}'
3656
3657 // Construct desired object and return
3658 Interface *inter = new MemInterface(base, index, scale, disp);
3659 return inter;
3660 }
3661
3662
3663 //------------------------------cond_interface_parse---------------------------
cond_interface_parse(void)3664 Interface *ADLParser::cond_interface_parse(void) {
3665 char *equal;
3666 char *not_equal;
3667 char *less;
3668 char *greater_equal;
3669 char *less_equal;
3670 char *greater;
3671 char *overflow;
3672 char *no_overflow;
3673 const char *equal_format = "eq";
3674 const char *not_equal_format = "ne";
3675 const char *less_format = "lt";
3676 const char *greater_equal_format = "ge";
3677 const char *less_equal_format = "le";
3678 const char *greater_format = "gt";
3679 const char *overflow_format = "o";
3680 const char *no_overflow_format = "no";
3681
3682 if (_curchar != '%') {
3683 parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n");
3684 return NULL;
3685 }
3686 next_char(); // Skip '%'
3687 if (_curchar != '{') {
3688 parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n");
3689 return NULL;
3690 }
3691 next_char(); // Skip '{'
3692 skipws();
3693 do {
3694 char *field = get_ident();
3695 if (field == NULL) {
3696 parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
3697 return NULL;
3698 }
3699 if ( strcmp(field,"equal") == 0 ) {
3700 equal = interface_field_parse(&equal_format);
3701 }
3702 else if ( strcmp(field,"not_equal") == 0 ) {
3703 not_equal = interface_field_parse(¬_equal_format);
3704 }
3705 else if ( strcmp(field,"less") == 0 ) {
3706 less = interface_field_parse(&less_format);
3707 }
3708 else if ( strcmp(field,"greater_equal") == 0 ) {
3709 greater_equal = interface_field_parse(&greater_equal_format);
3710 }
3711 else if ( strcmp(field,"less_equal") == 0 ) {
3712 less_equal = interface_field_parse(&less_equal_format);
3713 }
3714 else if ( strcmp(field,"greater") == 0 ) {
3715 greater = interface_field_parse(&greater_format);
3716 }
3717 else if ( strcmp(field,"overflow") == 0 ) {
3718 overflow = interface_field_parse(&overflow_format);
3719 }
3720 else if ( strcmp(field,"no_overflow") == 0 ) {
3721 no_overflow = interface_field_parse(&no_overflow_format);
3722 }
3723 else {
3724 parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
3725 return NULL;
3726 }
3727 } while( _curchar != '%' );
3728 next_char(); // Skip '%'
3729 if ( _curchar != '}' ) {
3730 parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n");
3731 return NULL;
3732 }
3733 next_char(); // Skip '}'
3734
3735 // Construct desired object and return
3736 Interface *inter = new CondInterface(equal, equal_format,
3737 not_equal, not_equal_format,
3738 less, less_format,
3739 greater_equal, greater_equal_format,
3740 less_equal, less_equal_format,
3741 greater, greater_format,
3742 overflow, overflow_format,
3743 no_overflow, no_overflow_format);
3744 return inter;
3745 }
3746
3747
3748 //------------------------------interface_field_parse--------------------------
interface_field_parse(const char ** format)3749 char *ADLParser::interface_field_parse(const char ** format) {
3750 char *iface_field = NULL;
3751
3752 // Get interface field
3753 skipws(); // Skip whitespace
3754 if (_curchar != '(') {
3755 parse_err(SYNERR, "Missing '(' at start of interface field.\n");
3756 return NULL;
3757 }
3758 next_char(); // move past '('
3759 skipws();
3760 if ( _curchar != '0' && _curchar != '$' ) {
3761 parse_err(SYNERR, "missing or invalid interface field contents.\n");
3762 return NULL;
3763 }
3764 iface_field = get_rep_var_ident();
3765 if (iface_field == NULL) {
3766 parse_err(SYNERR, "missing or invalid interface field contents.\n");
3767 return NULL;
3768 }
3769 skipws();
3770 if (format != NULL && _curchar == ',') {
3771 next_char();
3772 skipws();
3773 if (_curchar != '"') {
3774 parse_err(SYNERR, "Missing '\"' in field format .\n");
3775 return NULL;
3776 }
3777 next_char();
3778 char *start = _ptr; // Record start of the next string
3779 while ((_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) {
3780 if (_curchar == '\\') next_char(); // superquote
3781 if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented!
3782 next_char();
3783 }
3784 if (_curchar != '"') {
3785 parse_err(SYNERR, "Missing '\"' at end of field format .\n");
3786 return NULL;
3787 }
3788 // If a string was found, terminate it and record in FormatRule
3789 if ( start != _ptr ) {
3790 *_ptr = '\0'; // Terminate the string
3791 *format = start;
3792 }
3793 next_char();
3794 skipws();
3795 }
3796 if (_curchar != ')') {
3797 parse_err(SYNERR, "Missing ')' after interface field.\n");
3798 return NULL;
3799 }
3800 next_char(); // move past ')'
3801 skipws();
3802 if ( _curchar != ';' ) {
3803 parse_err(SYNERR, "Missing ';' at end of interface field.\n");
3804 return NULL;
3805 }
3806 next_char(); // move past ';'
3807 skipws(); // be friendly to interface_parse()
3808
3809 return iface_field;
3810 }
3811
3812
3813 //------------------------------match_parse------------------------------------
match_parse(FormDict & operands)3814 MatchRule *ADLParser::match_parse(FormDict &operands) {
3815 MatchRule *match; // Match Rule class for instruction/operand
3816 char *cnstr = NULL; // Code for constructor
3817 int depth = 0; // Counter for matching parentheses
3818 int numleaves = 0; // Counter for number of leaves in rule
3819
3820 // Parse the match rule tree
3821 MatchNode *mnode = matchNode_parse(operands, depth, numleaves, true);
3822
3823 // Either there is a block with a constructor, or a ';' here
3824 skipws(); // Skip whitespace
3825 if ( _curchar == ';' ) { // Semicolon is valid terminator
3826 cnstr = NULL; // no constructor for this form
3827 next_char(); // Move past the ';', replaced with '\0'
3828 }
3829 else if ((cnstr = find_cpp_block("match constructor")) == NULL ) {
3830 parse_err(SYNERR, "invalid construction of match rule\n"
3831 "Missing ';' or invalid '%%{' and '%%}' constructor\n");
3832 return NULL; // No MatchRule to return
3833 }
3834 if (_AD._adl_debug > 1)
3835 if (cnstr) fprintf(stderr,"Match Constructor: %s\n", cnstr);
3836 // Build new MatchRule object
3837 match = new MatchRule(_AD, mnode, depth, cnstr, numleaves);
3838 skipws(); // Skip any trailing whitespace
3839 return match; // Return MatchRule object
3840 }
3841
3842 //------------------------------format_parse-----------------------------------
format_parse(void)3843 FormatRule* ADLParser::format_parse(void) {
3844 char *desc = NULL;
3845 FormatRule *format = (new FormatRule(desc));
3846
3847 // Without expression form, MUST have a code block;
3848 skipws(); // Skip whitespace
3849 if ( _curchar == ';' ) { // Semicolon is valid terminator
3850 desc = NULL; // no constructor for this form
3851 next_char(); // Move past the ';', replaced with '\0'
3852 }
3853 else if ( _curchar == '%' && *(_ptr+1) == '{') {
3854 next_char(); // Move past the '%'
3855 next_char(); // Move past the '{'
3856
3857 skipws();
3858 if (_curchar == '$') {
3859 char* ident = get_rep_var_ident();
3860 if (strcmp(ident, "$$template") == 0) return template_parse();
3861 parse_err(SYNERR, "Unknown \"%s\" directive in format", ident);
3862 return NULL;
3863 }
3864 // Check for the opening '"' inside the format description
3865 if ( _curchar == '"' ) {
3866 next_char(); // Move past the initial '"'
3867 if( _curchar == '"' ) { // Handle empty format string case
3868 *_ptr = '\0'; // Terminate empty string
3869 format->_strings.addName(_ptr);
3870 }
3871
3872 // Collect the parts of the format description
3873 // (1) strings that are passed through to tty->print
3874 // (2) replacement/substitution variable, preceeded by a '$'
3875 // (3) multi-token ANSIY C style strings
3876 while ( true ) {
3877 if ( _curchar == '%' || _curchar == '\n' ) {
3878 if ( _curchar != '"' ) {
3879 parse_err(SYNERR, "missing '\"' at end of format block");
3880 return NULL;
3881 }
3882 }
3883
3884 // (1)
3885 // Check if there is a string to pass through to output
3886 char *start = _ptr; // Record start of the next string
3887 while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) {
3888 if (_curchar == '\\') {
3889 next_char(); // superquote
3890 if ((_curchar == '$') || (_curchar == '%'))
3891 // hack to avoid % escapes and warnings about undefined \ escapes
3892 *(_ptr-1) = _curchar;
3893 }
3894 if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented!
3895 next_char();
3896 }
3897 // If a string was found, terminate it and record in FormatRule
3898 if ( start != _ptr ) {
3899 *_ptr = '\0'; // Terminate the string
3900 format->_strings.addName(start);
3901 }
3902
3903 // (2)
3904 // If we are at a replacement variable,
3905 // copy it and record in FormatRule
3906 if ( _curchar == '$' ) {
3907 next_char(); // Move past the '$'
3908 char* rep_var = get_ident(); // Nil terminate the variable name
3909 rep_var = strdup(rep_var);// Copy the string
3910 *_ptr = _curchar; // and replace Nil with original character
3911 format->_rep_vars.addName(rep_var);
3912 // Add flag to _strings list indicating we should check _rep_vars
3913 format->_strings.addName(NameList::_signal);
3914 }
3915
3916 // (3)
3917 // Allow very long strings to be broken up,
3918 // using the ANSI C syntax "foo\n" <newline> "bar"
3919 if ( _curchar == '"') {
3920 next_char(); // Move past the '"'
3921 skipws(); // Skip white space before next string token
3922 if ( _curchar != '"') {
3923 break;
3924 } else {
3925 // Found one. Skip both " and the whitespace in between.
3926 next_char();
3927 }
3928 }
3929 } // end while part of format description
3930
3931 // Check for closing '"' and '%}' in format description
3932 skipws(); // Move to closing '%}'
3933 if ( _curchar != '%' ) {
3934 parse_err(SYNERR, "non-blank characters between closing '\"' and '%%' in format");
3935 return NULL;
3936 }
3937 } // Done with format description inside
3938
3939 skipws();
3940 // Past format description, at '%'
3941 if ( _curchar != '%' || *(_ptr+1) != '}' ) {
3942 parse_err(SYNERR, "missing '%%}' at end of format block");
3943 return NULL;
3944 }
3945 next_char(); // Move past the '%'
3946 next_char(); // Move past the '}'
3947 }
3948 else { // parameter list alone must terminate with a ';'
3949 parse_err(SYNERR, "missing ';' after Format expression");
3950 return NULL;
3951 }
3952 // Debug Stuff
3953 if (_AD._adl_debug > 1) fprintf(stderr,"Format Rule: %s\n", desc);
3954
3955 skipws();
3956 return format;
3957 }
3958
3959
3960 //------------------------------template_parse-----------------------------------
template_parse(void)3961 FormatRule* ADLParser::template_parse(void) {
3962 char *desc = NULL;
3963 FormatRule *format = (new FormatRule(desc));
3964
3965 skipws();
3966 while ( (_curchar != '%') && (*(_ptr+1) != '}') ) {
3967
3968 // (1)
3969 // Check if there is a string to pass through to output
3970 {
3971 char *start = _ptr; // Record start of the next string
3972 while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {
3973 // If at the start of a comment, skip past it
3974 if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {
3975 skipws_no_preproc();
3976 } else {
3977 // ELSE advance to the next character, or start of the next line
3978 next_char_or_line();
3979 }
3980 }
3981 // If a string was found, terminate it and record in EncClass
3982 if ( start != _ptr ) {
3983 *_ptr = '\0'; // Terminate the string
3984 // Add flag to _strings list indicating we should check _rep_vars
3985 format->_strings.addName(NameList::_signal2);
3986 format->_strings.addName(start);
3987 }
3988 }
3989
3990 // (2)
3991 // If we are at a replacement variable,
3992 // copy it and record in EncClass
3993 if ( _curchar == '$' ) {
3994 // Found replacement Variable
3995 char *rep_var = get_rep_var_ident_dup();
3996 if (strcmp(rep_var, "$emit") == 0) {
3997 // switch to normal format parsing
3998 next_char();
3999 next_char();
4000 skipws();
4001 // Check for the opening '"' inside the format description
4002 if ( _curchar == '"' ) {
4003 next_char(); // Move past the initial '"'
4004 if( _curchar == '"' ) { // Handle empty format string case
4005 *_ptr = '\0'; // Terminate empty string
4006 format->_strings.addName(_ptr);
4007 }
4008
4009 // Collect the parts of the format description
4010 // (1) strings that are passed through to tty->print
4011 // (2) replacement/substitution variable, preceeded by a '$'
4012 // (3) multi-token ANSIY C style strings
4013 while ( true ) {
4014 if ( _curchar == '%' || _curchar == '\n' ) {
4015 parse_err(SYNERR, "missing '\"' at end of format block");
4016 return NULL;
4017 }
4018
4019 // (1)
4020 // Check if there is a string to pass through to output
4021 char *start = _ptr; // Record start of the next string
4022 while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) {
4023 if (_curchar == '\\') next_char(); // superquote
4024 if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented!
4025 next_char();
4026 }
4027 // If a string was found, terminate it and record in FormatRule
4028 if ( start != _ptr ) {
4029 *_ptr = '\0'; // Terminate the string
4030 format->_strings.addName(start);
4031 }
4032
4033 // (2)
4034 // If we are at a replacement variable,
4035 // copy it and record in FormatRule
4036 if ( _curchar == '$' ) {
4037 next_char(); // Move past the '$'
4038 char* next_rep_var = get_ident(); // Nil terminate the variable name
4039 next_rep_var = strdup(next_rep_var);// Copy the string
4040 *_ptr = _curchar; // and replace Nil with original character
4041 format->_rep_vars.addName(next_rep_var);
4042 // Add flag to _strings list indicating we should check _rep_vars
4043 format->_strings.addName(NameList::_signal);
4044 }
4045
4046 // (3)
4047 // Allow very long strings to be broken up,
4048 // using the ANSI C syntax "foo\n" <newline> "bar"
4049 if ( _curchar == '"') {
4050 next_char(); // Move past the '"'
4051 skipws(); // Skip white space before next string token
4052 if ( _curchar != '"') {
4053 break;
4054 } else {
4055 // Found one. Skip both " and the whitespace in between.
4056 next_char();
4057 }
4058 }
4059 } // end while part of format description
4060 }
4061 } else {
4062 // Add flag to _strings list indicating we should check _rep_vars
4063 format->_rep_vars.addName(rep_var);
4064 // Add flag to _strings list indicating we should check _rep_vars
4065 format->_strings.addName(NameList::_signal3);
4066 }
4067 } // end while part of format description
4068 }
4069
4070 skipws();
4071 // Past format description, at '%'
4072 if ( _curchar != '%' || *(_ptr+1) != '}' ) {
4073 parse_err(SYNERR, "missing '%%}' at end of format block");
4074 return NULL;
4075 }
4076 next_char(); // Move past the '%'
4077 next_char(); // Move past the '}'
4078
4079 // Debug Stuff
4080 if (_AD._adl_debug > 1) fprintf(stderr,"Format Rule: %s\n", desc);
4081
4082 skipws();
4083 return format;
4084 }
4085
4086
4087 //------------------------------effect_parse-----------------------------------
effect_parse(InstructForm * instr)4088 void ADLParser::effect_parse(InstructForm *instr) {
4089 char* desc = NULL;
4090
4091 skipws(); // Skip whitespace
4092 if (_curchar != '(') {
4093 parse_err(SYNERR, "missing '(' in effect definition\n");
4094 return;
4095 }
4096 // Get list of effect-operand pairs and insert into dictionary
4097 else get_effectlist(instr->_effects, instr->_localNames, instr->_has_call);
4098
4099 // Debug Stuff
4100 if (_AD._adl_debug > 1) fprintf(stderr,"Effect description: %s\n", desc);
4101 if (_curchar != ';') {
4102 parse_err(SYNERR, "missing ';' in Effect definition\n");
4103 }
4104 next_char(); // Skip ';'
4105
4106 }
4107
4108 //------------------------------expand_parse-----------------------------------
expand_parse(InstructForm * instr)4109 ExpandRule* ADLParser::expand_parse(InstructForm *instr) {
4110 char *ident, *ident2;
4111 NameAndList *instr_and_operands = NULL;
4112 ExpandRule *exp = new ExpandRule();
4113
4114 // Expand is a block containing an ordered list of operands with initializers,
4115 // or instructions, each of which has an ordered list of operands.
4116 // Check for block delimiter
4117 skipws(); // Skip leading whitespace
4118 if ((_curchar != '%')
4119 || (next_char(), (_curchar != '{')) ) { // If not open block
4120 parse_err(SYNERR, "missing '%%{' in expand definition\n");
4121 return(NULL);
4122 }
4123 next_char(); // Maintain the invariant
4124 do {
4125 ident = get_ident(); // Grab next identifier
4126 if (ident == NULL) {
4127 parse_err(SYNERR, "identifier expected at %c\n", _curchar);
4128 continue;
4129 }
4130
4131 // Check whether we should parse an instruction or operand.
4132 const Form *form = _globalNames[ident];
4133 bool parse_oper = false;
4134 bool parse_ins = false;
4135 if (form == NULL) {
4136 skipws();
4137 // Check whether this looks like an instruction specification. If so,
4138 // just parse the instruction. The declaration of the instruction is
4139 // not needed here.
4140 if (_curchar == '(') parse_ins = true;
4141 } else if (form->is_instruction()) {
4142 parse_ins = true;
4143 } else if (form->is_operand()) {
4144 parse_oper = true;
4145 } else {
4146 parse_err(SYNERR, "instruction/operand name expected at %s\n", ident);
4147 continue;
4148 }
4149
4150 if (parse_oper) {
4151 // This is a new operand
4152 OperandForm *oper = form->is_operand();
4153 if (oper == NULL) {
4154 parse_err(SYNERR, "instruction/operand name expected at %s\n", ident);
4155 continue;
4156 }
4157 // Throw the operand on the _newopers list
4158 skipws();
4159 ident = get_unique_ident(instr->_localNames,"Operand");
4160 if (ident == NULL) {
4161 parse_err(SYNERR, "identifier expected at %c\n", _curchar);
4162 continue;
4163 }
4164 exp->_newopers.addName(ident);
4165 // Add new operand to LocalNames
4166 instr->_localNames.Insert(ident, oper);
4167 // Grab any constructor code and save as a string
4168 char *c = NULL;
4169 skipws();
4170 if (_curchar == '%') { // Need a constructor for the operand
4171 c = find_cpp_block("Operand Constructor");
4172 if (c == NULL) {
4173 parse_err(SYNERR, "Invalid code block for operand constructor\n", _curchar);
4174 continue;
4175 }
4176 // Add constructor to _newopconst Dict
4177 exp->_newopconst.Insert(ident, c);
4178 }
4179 else if (_curchar != ';') { // If no constructor, need a ;
4180 parse_err(SYNERR, "Missing ; in expand rule operand declaration\n");
4181 continue;
4182 }
4183 else next_char(); // Skip the ;
4184 skipws();
4185 }
4186 else {
4187 assert(parse_ins, "sanity");
4188 // Add instruction to list
4189 instr_and_operands = new NameAndList(ident);
4190 // Grab operands, build nameList of them, and then put into dictionary
4191 skipws();
4192 if (_curchar != '(') { // Check for parenthesized operand list
4193 parse_err(SYNERR, "missing '(' in expand instruction declaration\n");
4194 continue;
4195 }
4196 do {
4197 next_char(); // skip open paren & comma characters
4198 skipws();
4199 if (_curchar == ')') break;
4200 ident2 = get_ident();
4201 skipws();
4202 if (ident2 == NULL) {
4203 parse_err(SYNERR, "identifier expected at %c\n", _curchar);
4204 continue;
4205 } // Check that you have a valid operand
4206 const Form *form2 = instr->_localNames[ident2];
4207 if (!form2) {
4208 parse_err(SYNERR, "operand name expected at %s\n", ident2);
4209 continue;
4210 }
4211 OperandForm *oper = form2->is_operand();
4212 if (oper == NULL && !form2->is_opclass()) {
4213 parse_err(SYNERR, "operand name expected at %s\n", ident2);
4214 continue;
4215 } // Add operand to list
4216 instr_and_operands->add_entry(ident2);
4217 } while(_curchar == ',');
4218 if (_curchar != ')') {
4219 parse_err(SYNERR, "missing ')'in expand instruction declaration\n");
4220 continue;
4221 }
4222 next_char();
4223 if (_curchar != ';') {
4224 parse_err(SYNERR, "missing ';'in expand instruction declaration\n");
4225 continue;
4226 }
4227 next_char();
4228
4229 // Record both instruction name and its operand list
4230 exp->add_instruction(instr_and_operands);
4231
4232 skipws();
4233 }
4234
4235 } while(_curchar != '%');
4236 next_char();
4237 if (_curchar != '}') {
4238 parse_err(SYNERR, "missing '%%}' in expand rule definition\n");
4239 return(NULL);
4240 }
4241 next_char();
4242
4243 // Debug Stuff
4244 if (_AD._adl_debug > 1) fprintf(stderr,"Expand Rule:\n");
4245
4246 skipws();
4247 return (exp);
4248 }
4249
4250 //------------------------------rewrite_parse----------------------------------
rewrite_parse(void)4251 RewriteRule* ADLParser::rewrite_parse(void) {
4252 char* params = NULL;
4253 char* desc = NULL;
4254
4255
4256 // This feature targeted for second generation description language.
4257
4258 skipws(); // Skip whitespace
4259 // Get parameters for rewrite
4260 if ((params = get_paren_expr("rewrite parameters")) == NULL) {
4261 parse_err(SYNERR, "missing '(' in rewrite rule\n");
4262 return NULL;
4263 }
4264 // Debug Stuff
4265 if (_AD._adl_debug > 1) fprintf(stderr,"Rewrite parameters: %s\n", params);
4266
4267 // For now, grab entire block;
4268 skipws();
4269 if ( (desc = find_cpp_block("rewrite block")) == NULL ) {
4270 parse_err(SYNERR, "incorrect or missing block for 'rewrite'.\n");
4271 return NULL;
4272 }
4273 // Debug Stuff
4274 if (_AD._adl_debug > 1) fprintf(stderr,"Rewrite Rule: %s\n", desc);
4275
4276 skipws();
4277 return (new RewriteRule(params,desc));
4278 }
4279
4280 //------------------------------attr_parse-------------------------------------
attr_parse(char * ident)4281 Attribute *ADLParser::attr_parse(char* ident) {
4282 Attribute *attrib; // Attribute class
4283 char *cost = NULL; // String representation of cost attribute
4284
4285 skipws(); // Skip leading whitespace
4286 if ( (cost = get_paren_expr("attribute")) == NULL ) {
4287 parse_err(SYNERR, "incorrect or missing expression for 'attribute'\n");
4288 return NULL;
4289 }
4290 // Debug Stuff
4291 if (_AD._adl_debug > 1) fprintf(stderr,"Attribute: %s\n", cost);
4292 if (_curchar != ';') {
4293 parse_err(SYNERR, "missing ';' in attribute definition\n");
4294 return NULL;
4295 }
4296 next_char(); // Point after the terminator
4297
4298 skipws();
4299 attrib = new Attribute(ident,cost,INS_ATTR); // Build new predicate object
4300 return attrib;
4301 }
4302
4303
4304 //------------------------------matchNode_parse--------------------------------
matchNode_parse(FormDict & operands,int & depth,int & numleaves,bool atroot)4305 MatchNode *ADLParser::matchNode_parse(FormDict &operands, int &depth, int &numleaves, bool atroot) {
4306 // Count depth of parenthesis nesting for both left and right children
4307 int lParens = depth;
4308 int rParens = depth;
4309
4310 // MatchNode objects for left, right, and root of subtree.
4311 MatchNode *lChild = NULL;
4312 MatchNode *rChild = NULL;
4313 char *token; // Identifier which may be opcode or operand
4314
4315 // Match expression starts with a '('
4316 if (cur_char() != '(')
4317 return NULL;
4318
4319 next_char(); // advance past '('
4320
4321 // Parse the opcode
4322 token = get_ident(); // Get identifier, opcode
4323 if (token == NULL) {
4324 parse_err(SYNERR, "missing opcode in match expression\n");
4325 return NULL;
4326 }
4327
4328 // Take note if we see one of a few special operations - those that are
4329 // treated differently on different architectures in the sense that on
4330 // one architecture there is a match rule and on another there isn't (so
4331 // a call will eventually be generated).
4332
4333 for (int i = _last_machine_leaf + 1; i < _last_opcode; i++) {
4334 if (strcmp(token, NodeClassNames[i]) == 0) {
4335 _AD.has_match_rule(i, true);
4336 }
4337 }
4338
4339 // Lookup the root value in the operands dict to perform substitution
4340 const char *result = NULL; // Result type will be filled in later
4341 const char *name = token; // local name associated with this node
4342 const char *operation = token; // remember valid operation for later
4343 const Form *form = operands[token];
4344 OpClassForm *opcForm = form ? form->is_opclass() : NULL;
4345 if (opcForm != NULL) {
4346 // If this token is an entry in the local names table, record its type
4347 if (!opcForm->ideal_only()) {
4348 operation = opcForm->_ident;
4349 result = operation; // Operands result in their own type
4350 }
4351 // Otherwise it is an ideal type, and so, has no local name
4352 else name = NULL;
4353 }
4354
4355 // Parse the operands
4356 skipws();
4357 if (cur_char() != ')') {
4358
4359 // Parse the left child
4360 if (strcmp(operation,"Set"))
4361 lChild = matchChild_parse(operands, lParens, numleaves, false);
4362 else
4363 lChild = matchChild_parse(operands, lParens, numleaves, true);
4364
4365 skipws();
4366 if (cur_char() != ')' ) {
4367 if(strcmp(operation, "Set"))
4368 rChild = matchChild_parse(operands,rParens,numleaves,false);
4369 else
4370 rChild = matchChild_parse(operands,rParens,numleaves,true);
4371 }
4372 }
4373
4374 // Check for required ')'
4375 skipws();
4376 if (cur_char() != ')') {
4377 parse_err(SYNERR, "missing ')' in match expression\n");
4378 return NULL;
4379 }
4380 next_char(); // skip the ')'
4381
4382 MatchNode* mroot = new MatchNode(_AD,result,name,operation,lChild,rChild);
4383
4384 // If not the root, reduce this subtree to an internal operand
4385 if (!atroot) {
4386 mroot->build_internalop();
4387 }
4388 // depth is greater of left and right paths.
4389 depth = (lParens > rParens) ? lParens : rParens;
4390
4391 return mroot;
4392 }
4393
4394
4395 //------------------------------matchChild_parse-------------------------------
matchChild_parse(FormDict & operands,int & parens,int & numleaves,bool atroot)4396 MatchNode *ADLParser::matchChild_parse(FormDict &operands, int &parens, int &numleaves, bool atroot) {
4397 MatchNode *child = NULL;
4398 const char *result = NULL;
4399 const char *token = NULL;
4400 const char *opType = NULL;
4401
4402 if (cur_char() == '(') { // child is an operation
4403 ++parens;
4404 child = matchNode_parse(operands, parens, numleaves, atroot);
4405 }
4406 else { // child is an operand
4407 token = get_ident();
4408 const Form *form = operands[token];
4409 OpClassForm *opcForm = form ? form->is_opclass() : NULL;
4410 if (opcForm != NULL) {
4411 opType = opcForm->_ident;
4412 result = opcForm->_ident; // an operand's result matches its type
4413 } else {
4414 parse_err(SYNERR, "undefined operand %s in match rule\n", token);
4415 return NULL;
4416 }
4417
4418 if (opType == NULL) {
4419 parse_err(SYNERR, "missing type for argument '%s'\n", token);
4420 }
4421
4422 child = new MatchNode(_AD, result, token, opType);
4423 ++numleaves;
4424 }
4425
4426 return child;
4427 }
4428
4429
4430
4431 // ******************** Private Utility Functions *************************
4432
4433
find_cpp_block(const char * description)4434 char* ADLParser::find_cpp_block(const char* description) {
4435 char *next; // Pointer for finding block delimiters
4436 char* cppBlock = NULL; // Beginning of C++ code block
4437
4438 if (_curchar == '%') { // Encoding is a C++ expression
4439 next_char();
4440 if (_curchar != '{') {
4441 parse_err(SYNERR, "missing '{' in %s \n", description);
4442 return NULL;
4443 }
4444 next_char(); // Skip block delimiter
4445 skipws_no_preproc(); // Skip leading whitespace
4446 cppBlock = _ptr; // Point to start of expression
4447 int line = linenum();
4448 next = _ptr + 1;
4449 while(((_curchar != '%') || (*next != '}')) && (_curchar != '\0')) {
4450 next_char_or_line();
4451 next = _ptr+1; // Maintain the next pointer
4452 } // Grab string
4453 if (_curchar == '\0') {
4454 parse_err(SYNERR, "invalid termination of %s \n", description);
4455 return NULL;
4456 }
4457 *_ptr = '\0'; // Terminate string
4458 _ptr += 2; // Skip block delimiter
4459 _curchar = *_ptr; // Maintain invariant
4460
4461 // Prepend location descriptor, for debugging.
4462 if (_AD._adlocation_debug) {
4463 char* location = get_line_string(line);
4464 char* end_loc = end_line_marker();
4465 char* result = (char *)malloc(strlen(location) + strlen(cppBlock) + strlen(end_loc) + 1);
4466 strcpy(result, location);
4467 strcat(result, cppBlock);
4468 strcat(result, end_loc);
4469 cppBlock = result;
4470 free(location);
4471 }
4472 }
4473
4474 return cppBlock;
4475 }
4476
4477 // Move to the closing token of the expression we are currently at,
4478 // as defined by stop_chars. Match parens and quotes.
get_expr(const char * desc,const char * stop_chars)4479 char* ADLParser::get_expr(const char *desc, const char *stop_chars) {
4480 char* expr = NULL;
4481 int paren = 0;
4482
4483 expr = _ptr;
4484 while (paren > 0 || !strchr(stop_chars, _curchar)) {
4485 if (_curchar == '(') { // Down level of nesting
4486 paren++; // Bump the parenthesis counter
4487 next_char(); // maintain the invariant
4488 }
4489 else if (_curchar == ')') { // Up one level of nesting
4490 if (paren == 0) {
4491 // Paren underflow: We didn't encounter the required stop-char.
4492 parse_err(SYNERR, "too many )'s, did not find %s after %s\n",
4493 stop_chars, desc);
4494 return NULL;
4495 }
4496 paren--; // Drop the parenthesis counter
4497 next_char(); // Maintain the invariant
4498 }
4499 else if (_curchar == '"' || _curchar == '\'') {
4500 int qchar = _curchar;
4501 while (true) {
4502 next_char();
4503 if (_curchar == qchar) { next_char(); break; }
4504 if (_curchar == '\\') next_char(); // superquote
4505 if (_curchar == '\n' || _curchar == '\0') {
4506 parse_err(SYNERR, "newline in string in %s\n", desc);
4507 return NULL;
4508 }
4509 }
4510 }
4511 else if (_curchar == '%' && (_ptr[1] == '{' || _ptr[1] == '}')) {
4512 // Make sure we do not stray into the next ADLC-level form.
4513 parse_err(SYNERR, "unexpected %%%c in %s\n", _ptr[1], desc);
4514 return NULL;
4515 }
4516 else if (_curchar == '\0') {
4517 parse_err(SYNERR, "unexpected EOF in %s\n", desc);
4518 return NULL;
4519 }
4520 else {
4521 // Always walk over whitespace, comments, preprocessor directives, etc.
4522 char* pre_skip_ptr = _ptr;
4523 skipws();
4524 // If the parser declined to make progress on whitespace,
4525 // skip the next character, which is therefore NOT whitespace.
4526 if (pre_skip_ptr == _ptr) {
4527 next_char();
4528 } else if (pre_skip_ptr+strlen(pre_skip_ptr) != _ptr+strlen(_ptr)) {
4529 parse_err(SYNERR, "unimplemented: preprocessor must not elide subexpression in %s", desc);
4530 }
4531 }
4532 }
4533
4534 assert(strchr(stop_chars, _curchar), "non-null return must be at stop-char");
4535 *_ptr = '\0'; // Replace ')' or other stop-char with '\0'
4536 return expr;
4537 }
4538
4539 // Helper function around get_expr
4540 // Sets _curchar to '(' so that get_paren_expr will search for a matching ')'
get_paren_expr(const char * description,bool include_location)4541 char *ADLParser::get_paren_expr(const char *description, bool include_location) {
4542 int line = linenum();
4543 if (_curchar != '(') // Escape if not valid starting position
4544 return NULL;
4545 next_char(); // Skip the required initial paren.
4546 char *token2 = get_expr(description, ")");
4547 if (_curchar == ')')
4548 next_char(); // Skip required final paren.
4549 int junk = 0;
4550 if (include_location && _AD._adlocation_debug && !is_int_token(token2, junk)) {
4551 // Prepend location descriptor, for debugging.
4552 char* location = get_line_string(line);
4553 char* end_loc = end_line_marker();
4554 char* result = (char *)malloc(strlen(location) + strlen(token2) + strlen(end_loc) + 1);
4555 strcpy(result, location);
4556 strcat(result, token2);
4557 strcat(result, end_loc);
4558 token2 = result;
4559 free(location);
4560 }
4561 return token2;
4562 }
4563
4564 //------------------------------get_ident_common-------------------------------
4565 // Looks for an identifier in the buffer, and turns it into a null terminated
4566 // string(still inside the file buffer). Returns a pointer to the string or
4567 // NULL if some other token is found instead.
get_ident_common(bool do_preproc)4568 char *ADLParser::get_ident_common(bool do_preproc) {
4569 register char c;
4570 char *start; // Pointer to start of token
4571 char *end; // Pointer to end of token
4572
4573 if( _curline == NULL ) // Return NULL at EOF.
4574 return NULL;
4575
4576 skipws_common(do_preproc); // Skip whitespace before identifier
4577 start = end = _ptr; // Start points at first character
4578 end--; // unwind end by one to prepare for loop
4579 do {
4580 end++; // Increment end pointer
4581 c = *end; // Grab character to test
4582 } while ( ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))
4583 || ((c >= '0') && (c <= '9'))
4584 || ((c == '_')) || ((c == ':')) || ((c == '#')) );
4585 if (start == end) { // We popped out on the first try
4586 // It can occur that `start' contains the rest of the input file.
4587 // In this case the output should be truncated.
4588 if (strlen(start) > 24) {
4589 char buf[32];
4590 strncpy(buf, start, 20);
4591 buf[20] = '\0';
4592 strcat(buf, "[...]");
4593 parse_err(SYNERR, "Identifier expected, but found '%s'.", buf);
4594 } else {
4595 parse_err(SYNERR, "Identifier expected, but found '%s'.", start);
4596 }
4597 start = NULL;
4598 }
4599 else {
4600 _curchar = c; // Save the first character of next token
4601 *end = '\0'; // NULL terminate the string in place
4602 }
4603 _ptr = end; // Reset _ptr to point to next char after token
4604
4605 // Make sure we do not try to use #defined identifiers. If start is
4606 // NULL an error was already reported.
4607 if (do_preproc && start != NULL) {
4608 const char* def = _AD.get_preproc_def(start);
4609 if (def != NULL && strcmp(def, start)) {
4610 const char* def1 = def;
4611 const char* def2 = _AD.get_preproc_def(def1);
4612 // implement up to 2 levels of #define
4613 if (def2 != NULL && strcmp(def2, def1)) {
4614 def = def2;
4615 const char* def3 = _AD.get_preproc_def(def2);
4616 if (def3 != NULL && strcmp(def3, def2) && strcmp(def3, def1)) {
4617 parse_err(SYNERR, "unimplemented: using %s defined as %s => %s => %s",
4618 start, def1, def2, def3);
4619 }
4620 }
4621 start = strdup(def);
4622 }
4623 }
4624
4625 return start; // Pointer to token in filebuf
4626 }
4627
4628 //------------------------------get_ident_dup----------------------------------
4629 // Looks for an identifier in the buffer, and returns a duplicate
4630 // or NULL if some other token is found instead.
get_ident_dup(void)4631 char *ADLParser::get_ident_dup(void) {
4632 char *ident = get_ident();
4633
4634 // Duplicate an identifier before returning and restore string.
4635 if( ident != NULL ) {
4636 ident = strdup(ident); // Copy the string
4637 *_ptr = _curchar; // and replace Nil with original character
4638 }
4639
4640 return ident;
4641 }
4642
4643 //----------------------get_ident_or_literal_constant--------------------------
4644 // Looks for an identifier in the buffer, or a parenthesized expression.
get_ident_or_literal_constant(const char * description)4645 char *ADLParser::get_ident_or_literal_constant(const char* description) {
4646 char* param = NULL;
4647 skipws();
4648 if (_curchar == '(') {
4649 // Grab a constant expression.
4650 param = get_paren_expr(description);
4651 if (param[0] != '(') {
4652 char* buf = (char*) malloc(strlen(param) + 3);
4653 sprintf(buf, "(%s)", param);
4654 param = buf;
4655 }
4656 assert(is_literal_constant(param),
4657 "expr must be recognizable as a constant");
4658 } else {
4659 param = get_ident();
4660 }
4661 return param;
4662 }
4663
4664 //------------------------------get_rep_var_ident-----------------------------
4665 // Do NOT duplicate,
4666 // Leave nil terminator in buffer
4667 // Preserve initial '$'(s) in string
get_rep_var_ident(void)4668 char *ADLParser::get_rep_var_ident(void) {
4669 // Remember starting point
4670 char *rep_var = _ptr;
4671
4672 // Check for replacement variable indicator '$' and pass if present
4673 if ( _curchar == '$' ) {
4674 next_char();
4675 }
4676 // Check for a subfield indicator, a second '$', and pass if present
4677 if ( _curchar == '$' ) {
4678 next_char();
4679 }
4680
4681 // Check for a control indicator, a third '$':
4682 if ( _curchar == '$' ) {
4683 next_char();
4684 }
4685
4686 // Check for more than three '$'s in sequence, SYNERR
4687 if( _curchar == '$' ) {
4688 parse_err(SYNERR, "Replacement variables and field specifiers can not start with '$$$$'");
4689 next_char();
4690 return NULL;
4691 }
4692
4693 // Nil terminate the variable name following the '$'
4694 char *rep_var_name = get_ident();
4695 assert( rep_var_name != NULL,
4696 "Missing identifier after replacement variable indicator '$'");
4697
4698 return rep_var;
4699 }
4700
4701
4702
4703 //------------------------------get_rep_var_ident_dup-------------------------
4704 // Return the next replacement variable identifier, skipping first '$'
4705 // given a pointer into a line of the buffer.
4706 // Null terminates string, still inside the file buffer,
4707 // Returns a pointer to a copy of the string, or NULL on failure
get_rep_var_ident_dup(void)4708 char *ADLParser::get_rep_var_ident_dup(void) {
4709 if( _curchar != '$' ) return NULL;
4710
4711 next_char(); // Move past the '$'
4712 char *rep_var = _ptr; // Remember starting point
4713
4714 // Check for a subfield indicator, a second '$':
4715 if ( _curchar == '$' ) {
4716 next_char();
4717 }
4718
4719 // Check for a control indicator, a third '$':
4720 if ( _curchar == '$' ) {
4721 next_char();
4722 }
4723
4724 // Check for more than three '$'s in sequence, SYNERR
4725 if( _curchar == '$' ) {
4726 parse_err(SYNERR, "Replacement variables and field specifiers can not start with '$$$$'");
4727 next_char();
4728 return NULL;
4729 }
4730
4731 // Nil terminate the variable name following the '$'
4732 char *rep_var_name = get_ident();
4733 assert( rep_var_name != NULL,
4734 "Missing identifier after replacement variable indicator '$'");
4735 rep_var = strdup(rep_var); // Copy the string
4736 *_ptr = _curchar; // and replace Nil with original character
4737
4738 return rep_var;
4739 }
4740
4741
4742 //------------------------------get_unique_ident------------------------------
4743 // Looks for an identifier in the buffer, terminates it with a NULL,
4744 // and checks that it is unique
get_unique_ident(FormDict & dict,const char * nameDescription)4745 char *ADLParser::get_unique_ident(FormDict& dict, const char* nameDescription){
4746 char* ident = get_ident();
4747
4748 if (ident == NULL) {
4749 parse_err(SYNERR, "missing %s identifier at %c\n", nameDescription, _curchar);
4750 }
4751 else {
4752 if (dict[ident] != NULL) {
4753 parse_err(SYNERR, "duplicate name %s for %s\n", ident, nameDescription);
4754 ident = NULL;
4755 }
4756 }
4757
4758 return ident;
4759 }
4760
4761
4762 //------------------------------get_int----------------------------------------
4763 // Looks for a character string integer in the buffer, and turns it into an int
4764 // invokes a parse_err if the next token is not an integer.
4765 // This routine does not leave the integer null-terminated.
get_int(void)4766 int ADLParser::get_int(void) {
4767 register char c;
4768 char *start; // Pointer to start of token
4769 char *end; // Pointer to end of token
4770 int result; // Storage for integer result
4771
4772 if( _curline == NULL ) // Return NULL at EOF.
4773 return 0;
4774
4775 skipws(); // Skip whitespace before identifier
4776 start = end = _ptr; // Start points at first character
4777 c = *end; // Grab character to test
4778 while ((c >= '0' && c <= '9') || (c == '-' && end == start)) {
4779 end++; // Increment end pointer
4780 c = *end; // Grab character to test
4781 }
4782 if (start == end) { // We popped out on the first try
4783 parse_err(SYNERR, "integer expected at %c\n", c);
4784 result = 0;
4785 }
4786 else {
4787 _curchar = c; // Save the first character of next token
4788 *end = '\0'; // NULL terminate the string in place
4789 result = atoi(start); // Convert the string to an integer
4790 *end = _curchar; // Restore buffer to original condition
4791 }
4792
4793 // Reset _ptr to next char after token
4794 _ptr = end;
4795
4796 return result; // integer
4797 }
4798
4799
4800 //------------------------------get_relation_dup------------------------------
4801 // Looks for a relational operator in the buffer
4802 // invokes a parse_err if the next token is not a relation
4803 // This routine creates a duplicate of the string in the buffer.
get_relation_dup(void)4804 char *ADLParser::get_relation_dup(void) {
4805 char *result = NULL; // relational operator being returned
4806
4807 if( _curline == NULL ) // Return NULL at EOF.
4808 return NULL;
4809
4810 skipws(); // Skip whitespace before relation
4811 char *start = _ptr; // Store start of relational operator
4812 char first = *_ptr; // the first character
4813 if( (first == '=') || (first == '!') || (first == '<') || (first == '>') ) {
4814 next_char();
4815 char second = *_ptr; // the second character
4816 if( second == '=' ) {
4817 next_char();
4818 char tmp = *_ptr;
4819 *_ptr = '\0'; // NULL terminate
4820 result = strdup(start); // Duplicate the string
4821 *_ptr = tmp; // restore buffer
4822 } else {
4823 parse_err(SYNERR, "relational operator expected at %s\n", _ptr);
4824 }
4825 } else {
4826 parse_err(SYNERR, "relational operator expected at %s\n", _ptr);
4827 }
4828
4829 return result;
4830 }
4831
4832
4833
4834 //------------------------------get_oplist-------------------------------------
4835 // Looks for identifier pairs where first must be the name of an operand, and
4836 // second must be a name unique in the scope of this instruction. Stores the
4837 // names with a pointer to the OpClassForm of their type in a local name table.
get_oplist(NameList & parameters,FormDict & operands)4838 void ADLParser::get_oplist(NameList ¶meters, FormDict &operands) {
4839 OpClassForm *opclass = NULL;
4840 char *ident = NULL;
4841
4842 do {
4843 next_char(); // skip open paren & comma characters
4844 skipws();
4845 if (_curchar == ')') break;
4846
4847 // Get operand type, and check it against global name table
4848 ident = get_ident();
4849 if (ident == NULL) {
4850 parse_err(SYNERR, "optype identifier expected at %c\n", _curchar);
4851 return;
4852 }
4853 else {
4854 const Form *form = _globalNames[ident];
4855 if( form == NULL ) {
4856 parse_err(SYNERR, "undefined operand type %s\n", ident);
4857 return;
4858 }
4859
4860 // Check for valid operand type
4861 OpClassForm *opc = form->is_opclass();
4862 OperandForm *oper = form->is_operand();
4863 if((oper == NULL) && (opc == NULL)) {
4864 parse_err(SYNERR, "identifier %s not operand type\n", ident);
4865 return;
4866 }
4867 opclass = opc;
4868 }
4869 // Debugging Stuff
4870 if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Type: %s\t", ident);
4871
4872 // Get name of operand and add it to local name table
4873 if( (ident = get_unique_ident(operands, "operand")) == NULL) {
4874 return;
4875 }
4876 // Parameter names must not be global names.
4877 if( _globalNames[ident] != NULL ) {
4878 parse_err(SYNERR, "Reuse of global name %s as operand.\n",ident);
4879 return;
4880 }
4881 operands.Insert(ident, opclass);
4882 parameters.addName(ident);
4883
4884 // Debugging Stuff
4885 if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident);
4886 skipws();
4887 } while(_curchar == ',');
4888
4889 if (_curchar != ')') parse_err(SYNERR, "missing ')'\n");
4890 else {
4891 next_char(); // set current character position past the close paren
4892 }
4893 }
4894
4895
4896 //------------------------------get_effectlist---------------------------------
4897 // Looks for identifier pairs where first must be the name of a pre-defined,
4898 // effect, and the second must be the name of an operand defined in the
4899 // operand list of this instruction. Stores the names with a pointer to the
4900 // effect form in a local effects table.
get_effectlist(FormDict & effects,FormDict & operands,bool & has_call)4901 void ADLParser::get_effectlist(FormDict &effects, FormDict &operands, bool& has_call) {
4902 OperandForm *opForm;
4903 Effect *eForm;
4904 char *ident;
4905
4906 do {
4907 next_char(); // skip open paren & comma characters
4908 skipws();
4909 if (_curchar == ')') break;
4910
4911 // Get effect type, and check it against global name table
4912 ident = get_ident();
4913 if (ident == NULL) {
4914 parse_err(SYNERR, "effect type identifier expected at %c\n", _curchar);
4915 return;
4916 }
4917 else {
4918 // Check for valid effect type
4919 const Form *form = _globalNames[ident];
4920 if( form == NULL ) {
4921 parse_err(SYNERR, "undefined effect type %s\n", ident);
4922 return;
4923 }
4924 else {
4925 if( (eForm = form->is_effect()) == NULL) {
4926 parse_err(SYNERR, "identifier %s not effect type\n", ident);
4927 return;
4928 }
4929 }
4930 }
4931 // Debugging Stuff
4932 if (_AD._adl_debug > 1) fprintf(stderr, "\tEffect Type: %s\t", ident);
4933 skipws();
4934 if (eForm->is(Component::CALL)) {
4935 if (_AD._adl_debug > 1) fprintf(stderr, "\n");
4936 has_call = true;
4937 } else {
4938 // Get name of operand and check that it is in the local name table
4939 if( (ident = get_unique_ident(effects, "effect")) == NULL) {
4940 parse_err(SYNERR, "missing operand identifier in effect list\n");
4941 return;
4942 }
4943 const Form *form = operands[ident];
4944 opForm = form ? form->is_operand() : NULL;
4945 if( opForm == NULL ) {
4946 if( form && form->is_opclass() ) {
4947 const char* cname = form->is_opclass()->_ident;
4948 parse_err(SYNERR, "operand classes are illegal in effect lists (found %s %s)\n", cname, ident);
4949 } else {
4950 parse_err(SYNERR, "undefined operand %s in effect list\n", ident);
4951 }
4952 return;
4953 }
4954 // Add the pair to the effects table
4955 effects.Insert(ident, eForm);
4956 // Debugging Stuff
4957 if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident);
4958 }
4959 skipws();
4960 } while(_curchar == ',');
4961
4962 if (_curchar != ')') parse_err(SYNERR, "missing ')'\n");
4963 else {
4964 next_char(); // set current character position past the close paren
4965 }
4966 }
4967
4968
4969 //-------------------------------preproc_line----------------------------------
4970 // A "#line" keyword has been seen, so parse the rest of the line.
preproc_line(void)4971 void ADLParser::preproc_line(void) {
4972 int line = get_int();
4973 skipws_no_preproc();
4974 const char* file = NULL;
4975 if (_curchar == '"') {
4976 next_char(); // Move past the initial '"'
4977 file = _ptr;
4978 while (true) {
4979 if (_curchar == '\n') {
4980 parse_err(SYNERR, "missing '\"' at end of #line directive");
4981 return;
4982 }
4983 if (_curchar == '"') {
4984 *_ptr = '\0'; // Terminate the string
4985 next_char();
4986 skipws_no_preproc();
4987 break;
4988 }
4989 next_char();
4990 }
4991 }
4992 ensure_end_of_line();
4993 if (file != NULL)
4994 _AD._ADL_file._name = file;
4995 _buf.set_linenum(line);
4996 }
4997
4998 //------------------------------preproc_define---------------------------------
4999 // A "#define" keyword has been seen, so parse the rest of the line.
preproc_define(void)5000 void ADLParser::preproc_define(void) {
5001 char* flag = get_ident_no_preproc();
5002 skipws_no_preproc();
5003 // only #define x y is supported for now
5004 char* def = get_ident_no_preproc();
5005 _AD.set_preproc_def(flag, def);
5006 skipws_no_preproc();
5007 if (_curchar != '\n') {
5008 parse_err(SYNERR, "non-identifier in preprocessor definition\n");
5009 }
5010 }
5011
5012 //------------------------------preproc_undef----------------------------------
5013 // An "#undef" keyword has been seen, so parse the rest of the line.
preproc_undef(void)5014 void ADLParser::preproc_undef(void) {
5015 char* flag = get_ident_no_preproc();
5016 skipws_no_preproc();
5017 ensure_end_of_line();
5018 _AD.set_preproc_def(flag, NULL);
5019 }
5020
5021
5022
5023 //------------------------------parse_err--------------------------------------
5024 // Issue a parser error message, and skip to the end of the current line
parse_err(int flag,const char * fmt,...)5025 void ADLParser::parse_err(int flag, const char *fmt, ...) {
5026 va_list args;
5027
5028 va_start(args, fmt);
5029 if (flag == 1)
5030 _AD._syntax_errs += _AD.emit_msg(0, flag, linenum(), fmt, args);
5031 else if (flag == 2)
5032 _AD._semantic_errs += _AD.emit_msg(0, flag, linenum(), fmt, args);
5033 else
5034 _AD._warnings += _AD.emit_msg(0, flag, linenum(), fmt, args);
5035
5036 int error_char = _curchar;
5037 char* error_ptr = _ptr+1;
5038 for(;*_ptr != '\n'; _ptr++) ; // Skip to the end of the current line
5039 _curchar = '\n';
5040 va_end(args);
5041 _AD._no_output = 1;
5042
5043 if (flag == 1) {
5044 char* error_tail = strchr(error_ptr, '\n');
5045 char tem = *error_ptr;
5046 error_ptr[-1] = '\0';
5047 char* error_head = error_ptr-1;
5048 while (error_head > _curline && *error_head) --error_head;
5049 if (error_tail) *error_tail = '\0';
5050 fprintf(stderr, "Error Context: %s>>>%c<<<%s\n",
5051 error_head, error_char, error_ptr);
5052 if (error_tail) *error_tail = '\n';
5053 error_ptr[-1] = tem;
5054 }
5055 }
5056
5057 //---------------------------ensure_start_of_line------------------------------
5058 // A preprocessor directive has been encountered. Be sure it has fallen at
5059 // the beginning of a line, or else report an error.
ensure_start_of_line(void)5060 void ADLParser::ensure_start_of_line(void) {
5061 if (_curchar == '\n') { next_line(); return; }
5062 assert( _ptr >= _curline && _ptr < _curline+strlen(_curline),
5063 "Must be able to find which line we are in" );
5064
5065 for (char *s = _curline; s < _ptr; s++) {
5066 if (*s > ' ') {
5067 parse_err(SYNERR, "'%c' must be at beginning of line\n", _curchar);
5068 break;
5069 }
5070 }
5071 }
5072
5073 //---------------------------ensure_end_of_line--------------------------------
5074 // A preprocessor directive has been parsed. Be sure there is no trailing
5075 // garbage at the end of this line. Set the scan point to the beginning of
5076 // the next line.
ensure_end_of_line(void)5077 void ADLParser::ensure_end_of_line(void) {
5078 skipws_no_preproc();
5079 if (_curchar != '\n' && _curchar != '\0') {
5080 parse_err(SYNERR, "garbage char '%c' at end of line\n", _curchar);
5081 } else {
5082 next_char_or_line();
5083 }
5084 }
5085
5086 //---------------------------handle_preproc------------------------------------
5087 // The '#' character introducing a preprocessor directive has been found.
5088 // Parse the whole directive name (e.g., #define, #endif) and take appropriate
5089 // action. If we are in an "untaken" span of text, simply keep track of
5090 // #ifdef nesting structure, so we can find out when to start taking text
5091 // again. (In this state, we "sort of support" C's #if directives, enough
5092 // to disregard their associated #else and #endif lines.) If we are in a
5093 // "taken" span of text, there are two cases: "#define" and "#undef"
5094 // directives are preserved and passed up to the caller, which eventually
5095 // passes control to the top-level parser loop, which handles #define and
5096 // #undef directly. (This prevents these directives from occurring in
5097 // arbitrary positions in the AD file--we require better structure than C.)
5098 // In the other case, and #ifdef, #ifndef, #else, or #endif is silently
5099 // processed as whitespace, with the "taken" state of the text correctly
5100 // updated. This routine returns "false" exactly in the case of a "taken"
5101 // #define or #undef, which tells the caller that a preprocessor token
5102 // has appeared which must be handled explicitly by the parse loop.
handle_preproc_token()5103 bool ADLParser::handle_preproc_token() {
5104 assert(*_ptr == '#', "must be at start of preproc");
5105 ensure_start_of_line();
5106 next_char();
5107 skipws_no_preproc();
5108 char* start_ident = _ptr;
5109 char* ident = (_curchar == '\n') ? NULL : get_ident_no_preproc();
5110 if (ident == NULL) {
5111 parse_err(SYNERR, "expected preprocessor command, got end of line\n");
5112 } else if (!strcmp(ident, "ifdef") ||
5113 !strcmp(ident, "ifndef")) {
5114 char* flag = get_ident_no_preproc();
5115 ensure_end_of_line();
5116 // Test the identifier only if we are already in taken code:
5117 bool flag_def = preproc_taken() && (_AD.get_preproc_def(flag) != NULL);
5118 bool now_taken = !strcmp(ident, "ifdef") ? flag_def : !flag_def;
5119 begin_if_def(now_taken);
5120 } else if (!strcmp(ident, "if")) {
5121 if (preproc_taken())
5122 parse_err(SYNERR, "unimplemented: #%s %s", ident, _ptr+1);
5123 next_line();
5124 // Intelligently skip this nested C preprocessor directive:
5125 begin_if_def(true);
5126 } else if (!strcmp(ident, "else")) {
5127 ensure_end_of_line();
5128 invert_if_def();
5129 } else if (!strcmp(ident, "endif")) {
5130 ensure_end_of_line();
5131 end_if_def();
5132 } else if (preproc_taken()) {
5133 // pass this token up to the main parser as "#define" or "#undef"
5134 _ptr = start_ident;
5135 _curchar = *--_ptr;
5136 if( _curchar != '#' ) {
5137 parse_err(SYNERR, "no space allowed after # in #define or #undef");
5138 assert(_curchar == '#', "no space allowed after # in #define or #undef");
5139 }
5140 return false;
5141 }
5142 return true;
5143 }
5144
5145 //---------------------------skipws_common-------------------------------------
5146 // Skip whitespace, including comments and newlines, while keeping an accurate
5147 // line count.
5148 // Maybe handle certain preprocessor constructs: #ifdef, #ifndef, #else, #endif
skipws_common(bool do_preproc)5149 void ADLParser::skipws_common(bool do_preproc) {
5150 char *start = _ptr;
5151 char *next = _ptr + 1;
5152
5153 if (*_ptr == '\0') {
5154 // Check for string terminator
5155 if (_curchar > ' ') return;
5156 if (_curchar == '\n') {
5157 if (!do_preproc) return; // let caller handle the newline
5158 next_line();
5159 _ptr = _curline; next = _ptr + 1;
5160 }
5161 else if (_curchar == '#' ||
5162 (_curchar == '/' && (*next == '/' || *next == '*'))) {
5163 parse_err(SYNERR, "unimplemented: comment token in a funny place");
5164 }
5165 }
5166 while(_curline != NULL) { // Check for end of file
5167 if (*_ptr == '\n') { // keep proper track of new lines
5168 if (!do_preproc) break; // let caller handle the newline
5169 next_line();
5170 _ptr = _curline; next = _ptr + 1;
5171 }
5172 else if ((*_ptr == '/') && (*next == '/')) // C++ comment
5173 do { _ptr++; next++; } while(*_ptr != '\n'); // So go to end of line
5174 else if ((*_ptr == '/') && (*next == '*')) { // C comment
5175 _ptr++; next++;
5176 do {
5177 _ptr++; next++;
5178 if (*_ptr == '\n') { // keep proper track of new lines
5179 next_line(); // skip newlines within comments
5180 if (_curline == NULL) { // check for end of file
5181 parse_err(SYNERR, "end-of-file detected inside comment\n");
5182 break;
5183 }
5184 _ptr = _curline; next = _ptr + 1;
5185 }
5186 } while(!((*_ptr == '*') && (*next == '/'))); // Go to end of comment
5187 _ptr = ++next; next++; // increment _ptr past comment end
5188 }
5189 else if (do_preproc && *_ptr == '#') {
5190 // Note that this calls skipws_common(false) recursively!
5191 bool preproc_handled = handle_preproc_token();
5192 if (!preproc_handled) {
5193 if (preproc_taken()) {
5194 return; // short circuit
5195 }
5196 ++_ptr; // skip the preprocessor character
5197 }
5198 next = _ptr+1;
5199 } else if(*_ptr > ' ' && !(do_preproc && !preproc_taken())) {
5200 break;
5201 }
5202 else if (*_ptr == '"' || *_ptr == '\'') {
5203 assert(do_preproc, "only skip strings if doing preproc");
5204 // skip untaken quoted string
5205 int qchar = *_ptr;
5206 while (true) {
5207 ++_ptr;
5208 if (*_ptr == qchar) { ++_ptr; break; }
5209 if (*_ptr == '\\') ++_ptr;
5210 if (*_ptr == '\n' || *_ptr == '\0') {
5211 parse_err(SYNERR, "newline in string");
5212 break;
5213 }
5214 }
5215 next = _ptr + 1;
5216 }
5217 else { ++_ptr; ++next; }
5218 }
5219 if( _curline != NULL ) // at end of file _curchar isn't valid
5220 _curchar = *_ptr; // reset _curchar to maintain invariant
5221 }
5222
5223 //---------------------------cur_char-----------------------------------------
cur_char()5224 char ADLParser::cur_char() {
5225 return (_curchar);
5226 }
5227
5228 //---------------------------next_char-----------------------------------------
next_char()5229 void ADLParser::next_char() {
5230 if (_curchar == '\n') parse_err(WARN, "must call next_line!");
5231 _curchar = *++_ptr;
5232 // if ( _curchar == '\n' ) {
5233 // next_line();
5234 // }
5235 }
5236
5237 //---------------------------next_char_or_line---------------------------------
next_char_or_line()5238 void ADLParser::next_char_or_line() {
5239 if ( _curchar != '\n' ) {
5240 _curchar = *++_ptr;
5241 } else {
5242 next_line();
5243 _ptr = _curline;
5244 _curchar = *_ptr; // maintain invariant
5245 }
5246 }
5247
5248 //---------------------------next_line-----------------------------------------
next_line()5249 void ADLParser::next_line() {
5250 _curline = _buf.get_line();
5251 _curchar = ' ';
5252 }
5253
5254 //------------------------get_line_string--------------------------------------
5255 // Prepended location descriptor, for debugging.
5256 // Must return a malloced string (that can be freed if desired).
get_line_string(int linenum)5257 char* ADLParser::get_line_string(int linenum) {
5258 const char* file = _AD._ADL_file._name;
5259 int line = linenum ? linenum : this->linenum();
5260 char* location = (char *)malloc(strlen(file) + 100);
5261 sprintf(location, "\n#line %d \"%s\"\n", line, file);
5262 return location;
5263 }
5264
5265 //-------------------------is_literal_constant---------------------------------
is_literal_constant(const char * param)5266 bool ADLParser::is_literal_constant(const char *param) {
5267 if (param[0] == 0) return false; // null string
5268 if (param[0] == '(') return true; // parenthesized expression
5269 if (param[0] == '0' && (param[1] == 'x' || param[1] == 'X')) {
5270 // Make sure it's a hex constant.
5271 int i = 2;
5272 do {
5273 if( !ADLParser::is_hex_digit(*(param+i)) ) return false;
5274 ++i;
5275 } while( *(param+i) != 0 );
5276 return true;
5277 }
5278 return false;
5279 }
5280
5281 //---------------------------is_hex_digit--------------------------------------
is_hex_digit(char digit)5282 bool ADLParser::is_hex_digit(char digit) {
5283 return ((digit >= '0') && (digit <= '9'))
5284 ||((digit >= 'a') && (digit <= 'f'))
5285 ||((digit >= 'A') && (digit <= 'F'));
5286 }
5287
5288 //---------------------------is_int_token--------------------------------------
is_int_token(const char * token,int & intval)5289 bool ADLParser::is_int_token(const char* token, int& intval) {
5290 const char* cp = token;
5291 while (*cp != '\0' && *cp <= ' ') cp++;
5292 if (*cp == '-') cp++;
5293 int ndigit = 0;
5294 while (*cp >= '0' && *cp <= '9') { cp++; ndigit++; }
5295 while (*cp != '\0' && *cp <= ' ') cp++;
5296 if (ndigit == 0 || *cp != '\0') {
5297 return false;
5298 }
5299 intval = atoi(token);
5300 return true;
5301 }
5302
skip_expr_ws(const char * str)5303 static const char* skip_expr_ws(const char* str) {
5304 const char * cp = str;
5305 while (cp[0]) {
5306 if (cp[0] <= ' ') {
5307 ++cp;
5308 } else if (cp[0] == '#') {
5309 ++cp;
5310 while (cp[0] == ' ') ++cp;
5311 assert(0 == strncmp(cp, "line", 4), "must be a #line directive");
5312 const char* eol = strchr(cp, '\n');
5313 assert(eol != NULL, "must find end of line");
5314 if (eol == NULL) eol = cp + strlen(cp);
5315 cp = eol;
5316 } else {
5317 break;
5318 }
5319 }
5320 return cp;
5321 }
5322
5323 //-----------------------equivalent_expressions--------------------------------
equivalent_expressions(const char * str1,const char * str2)5324 bool ADLParser::equivalent_expressions(const char* str1, const char* str2) {
5325 if (str1 == str2)
5326 return true;
5327 else if (str1 == NULL || str2 == NULL)
5328 return false;
5329 const char* cp1 = str1;
5330 const char* cp2 = str2;
5331 char in_quote = '\0';
5332 while (cp1[0] && cp2[0]) {
5333 if (!in_quote) {
5334 // skip spaces and/or cpp directives
5335 const char* cp1a = skip_expr_ws(cp1);
5336 const char* cp2a = skip_expr_ws(cp2);
5337 if (cp1a > cp1 && cp2a > cp2) {
5338 cp1 = cp1a; cp2 = cp2a;
5339 continue;
5340 }
5341 if (cp1a > cp1 || cp2a > cp2) break; // fail
5342 }
5343 // match one non-space char
5344 if (cp1[0] != cp2[0]) break; // fail
5345 char ch = cp1[0];
5346 cp1++; cp2++;
5347 // watch for quotes
5348 if (in_quote && ch == '\\') {
5349 if (cp1[0] != cp2[0]) break; // fail
5350 if (!cp1[0]) break;
5351 cp1++; cp2++;
5352 }
5353 if (in_quote && ch == in_quote) {
5354 in_quote = '\0';
5355 } else if (!in_quote && (ch == '"' || ch == '\'')) {
5356 in_quote = ch;
5357 }
5358 }
5359 return (!cp1[0] && !cp2[0]);
5360 }
5361
5362
5363 //-------------------------------trim------------------------------------------
trim(char * & token)5364 void ADLParser::trim(char* &token) {
5365 while (*token <= ' ') token++;
5366 char* end = token + strlen(token);
5367 while (end > token && *(end-1) <= ' ') --end;
5368 *end = '\0';
5369 }
5370