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