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