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