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