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