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