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