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