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