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