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