File: | jdk/src/hotspot/share/adlc/adlparse.cpp |
Warning: | line 125, 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 == NULL__null) { // Empty line | |||
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 | } |