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