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