Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/share/adlc/adlparse.cpp
41145 views
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; // No pointers into buffer yet
37
38
_preproc_depth = 0;
39
_preproc_not_taken = 0;
40
41
// Delimit command-line definitions from in-file definitions:
42
_AD._preproc_list.add_signal();
43
}
44
45
//------------------------------~ADLParser-------------------------------------
46
// Delete an ADL parser.
47
ADLParser::~ADLParser() {
48
if (!_AD._quiet_mode)
49
fprintf(stderr,"---------------------------- Errors and Warnings ----------------------------\n");
50
#ifndef ASSERT
51
if (!_AD._quiet_mode) {
52
fprintf(stderr, "**************************************************************\n");
53
fprintf(stderr, "***** WARNING: ASSERT is undefined, assertions disabled. *****\n");
54
fprintf(stderr, "**************************************************************\n");
55
}
56
#endif
57
if( _AD._syntax_errs + _AD._semantic_errs + _AD._warnings == 0 ) {
58
if (!_AD._quiet_mode)
59
fprintf(stderr,"No errors or warnings to report from phase-1 parse.\n" );
60
}
61
else {
62
if( _AD._syntax_errs ) { // Any syntax errors?
63
fprintf(stderr,"%s: Found %d syntax error", _buf._fp->_name, _AD._syntax_errs);
64
if( _AD._syntax_errs > 1 ) fprintf(stderr,"s.\n\n");
65
else fprintf(stderr,".\n\n");
66
}
67
if( _AD._semantic_errs ) { // Any semantic errors?
68
fprintf(stderr,"%s: Found %d semantic error", _buf._fp->_name, _AD._semantic_errs);
69
if( _AD._semantic_errs > 1 ) fprintf(stderr,"s.\n\n");
70
else fprintf(stderr,".\n\n");
71
}
72
if( _AD._warnings ) { // Any warnings?
73
fprintf(stderr,"%s: Found %d warning", _buf._fp->_name, _AD._warnings);
74
if( _AD._warnings > 1 ) fprintf(stderr,"s.\n\n");
75
else fprintf(stderr,".\n\n");
76
}
77
}
78
if (!_AD._quiet_mode)
79
fprintf(stderr,"-----------------------------------------------------------------------------\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; 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) { // 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(SYNERR, "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) {
123
parse_err(SEMERR, "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(SYNERR, "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) {
136
parse_err(SEMERR, "Did not declare 'ins_cost' attribute");
137
}
138
if (_globalNames[AttributeForm::_op_cost] == NULL) {
139
parse_err(SEMERR, "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 )
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(stderr,"Parsing Instruction Form %s\n", ident);
162
163
// Then get the operands
164
skipws();
165
if (_curchar != '(') {
166
parse_err(SYNERR, "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(SYNERR, "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) {
181
parse_err(SYNERR, "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) {
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)
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(SYNERR, "unique match rule expected for %s\n", rule->_name);
211
return;
212
}
213
assert(match_rules_cnt < 100," too many match rule clones");
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(SYNERR, "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(SYNERR, "Instructions do not specify a constraint\n");
235
}
236
else if (!strcmp(ident, "construct")) {
237
parse_err(SYNERR, "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(SYNERR, "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;
248
if (attr && (attr->_atype == INS_ATTR)) {
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(SYNERR, "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(SYNERR, "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(WARN, "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(WARN, "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) {
286
rule = rule->_next;
287
while (rule != 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(stderr,"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; // 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 || instr->_matrule->_rChild == 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;
328
const char *name = NULL;
329
const char *optype = 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;
334
const char *name2 = NULL;
335
const char *optype2 = 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)
339
parse_err(SYNERR, "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) {
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) {
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 || frm->is_operand()->_predicate == 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) {
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) {
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;
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) {
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) {
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 )
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(stderr,"Parsing Operand Form %s\n", ident);
425
426
// Get the component operands
427
skipws();
428
if (_curchar != '(') {
429
parse_err(SYNERR, "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(SYNERR, "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) {
443
parse_err(SYNERR, "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(SYNERR, "Operands specify 'encode', not 'ins_encode'\n");
469
}
470
else if (!strcmp(ident, "opcode")) {
471
parse_err(SYNERR, "Operands do not specify an opcode\n");
472
}
473
else if (!strcmp(ident, "effect")) {
474
parse_err(SYNERR, "Operands do not specify an effect\n");
475
}
476
else if (!strcmp(ident, "expand")) {
477
parse_err(SYNERR, "Operands do not specify an expand\n");
478
}
479
else if (!strcmp(ident, "rewrite")) {
480
parse_err(SYNERR, "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) &&
488
(attr->_atype == OP_ATTR)) oper->_attribs = attr_parse(ident);
489
else {
490
parse_err(SYNERR, "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(SYNERR, "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 )
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(stderr,"Parsing Operand Class Form %s\n", ident);
520
521
// Get the list of operands
522
skipws();
523
if (_curchar != '(') {
524
parse_err(SYNERR, "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) {
531
parse_err(SYNERR, "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;
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(SYNERR, "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(SYNERR, "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(SYNERR, "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 )
572
return;
573
// Debugging Stuff
574
if (_AD._adl_debug > 1) fprintf(stderr,"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) {
579
parse_err(SYNERR, "missing '(' in ins_attrib definition\n");
580
return;
581
}
582
// Debug Stuff
583
if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr);
584
585
// Check for terminator
586
if (_curchar != ';') {
587
parse_err(SYNERR, "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_ATTR, 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 )
607
return;
608
// Debugging Stuff
609
if (_AD._adl_debug > 1) fprintf(stderr,"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) {
614
parse_err(SYNERR, "missing '(' in op_attrib definition\n");
615
return;
616
}
617
// Debug Stuff
618
if (_AD._adl_debug > 1) fprintf(stderr,"Attribute Expression: %s\n", aexpr);
619
620
// Check for terminator
621
if (_curchar != ';') {
622
parse_err(SYNERR, "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_ATTR, 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) {
643
parse_err(SYNERR, "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(SYNERR, "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; // Name of definition
664
char *value = NULL; // its value,
665
int int_value = -1; // positive values only
666
char *description = NULL; // textual description
667
668
// Get definition name
669
skipws(); // Skip whitespace
670
name = get_ident();
671
if (name == NULL) {
672
parse_err(SYNERR, "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) {
684
parse_err(SYNERR, "missing value in int_def\n");
685
return;
686
}
687
if( !is_int_token(value, int_value) ) {
688
parse_err(SYNERR, "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) {
699
parse_err(SYNERR, "invalid or missing description in int_def\n");
700
return;
701
}
702
trim(description);
703
}
704
705
if (_curchar != ')') {
706
parse_err(SYNERR, "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(SYNERR, "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(stderr,"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) {
730
parse_err(SYNERR, "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; // String representation of encode rule
742
743
skipws(); // Skip leading whitespace
744
if ( (rule = find_cpp_block("source block")) == NULL ) {
745
parse_err(SYNERR, "incorrect or missing block for 'source'.\n");
746
return;
747
}
748
// Debug Stuff
749
if (_AD._adl_debug > 1) fprintf(stderr,"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; // String representation of encode rule
765
766
skipws(); // Skip leading whitespace
767
if ( (rule = find_cpp_block("source_hpp block")) == NULL ) {
768
parse_err(SYNERR, "incorrect or missing block for 'source_hpp'.\n");
769
return;
770
}
771
// Debug Stuff
772
if (_AD._adl_debug > 1) fprintf(stderr,"Header Form: %s\n", rule);
773
774
if (_AD.get_registers() == 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) {
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) {
801
parse_err(SYNERR, "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(SYNERR, "bad token %s inside register block.\n", token); break; }
810
skipws();
811
}
812
}
813
else {
814
parse_err(SYNERR, "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) {
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) {
837
parse_err(SYNERR, "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(SYNERR, "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) {
858
parse_err(SYNERR, "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; // parameter type
870
char *pName = 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) {
879
parse_err(SYNERR, "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) {
887
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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(stderr,"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; // 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) {
985
parse_err(SYNERR, "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(WARN, "Using obsolete Token, compiler_method_oop_reg");
1002
skipws();
1003
}
1004
if (strcmp(token,"interpreter_method_oop_reg")==0) {
1005
parse_err(WARN, "Using obsolete Token, interpreter_method_oop_reg");
1006
skipws();
1007
}
1008
if (strcmp(token,"interpreter_method_reg")==0) {
1009
parse_err(WARN, "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(WARN, "Using obsolete token, in_preserve_stack_slots");
1023
skipws();
1024
}
1025
if (strcmp(token,"out_preserve_stack_slots")==0) {
1026
parse_err(WARN, "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(WARN, "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(WARN, "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(SYNERR, "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) {
1062
parse_err(SYNERR, "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) {
1071
parse_err(SYNERR, "missing alignment definition in frame section.\n");
1072
return;
1073
}
1074
if(frame->_return_addr == NULL) {
1075
parse_err(SYNERR, "missing return address location in frame section.\n");
1076
return;
1077
}
1078
if(frame->_varargs_C_out_slots_killed == NULL) {
1079
parse_err(SYNERR, "missing varargs C out slots killed definition in frame section.\n");
1080
return;
1081
}
1082
if(frame->_return_value == NULL) {
1083
parse_err(SYNERR, "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) {
1088
frame->_c_frame_pointer = frame->_frame_pointer;
1089
}
1090
if(frame->_c_return_addr == 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) {
1095
frame->_c_return_value = frame->_return_value;
1096
}
1097
1098
// Debug Stuff
1099
if (_AD._adl_debug > 1) fprintf(stderr,"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;
1145
if(_curchar == '(') {
1146
next_char();
1147
skipws();
1148
token = get_expr(description, ")");
1149
if (token == NULL) {
1150
parse_err(SYNERR, "missing value inside %s.\n", description);
1151
return NULL;
1152
}
1153
next_char(); // skip the close paren
1154
if(_curchar != ';') { // check for semi-colon
1155
parse_err(SYNERR, "missing %c in.\n", ';', description);
1156
return NULL;
1157
}
1158
next_char(); // skip the semi-colon
1159
}
1160
else {
1161
parse_err(SYNERR, "Missing %c in.\n", '(', description);
1162
return 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) {
1177
parse_err(SYNERR, "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(SYNERR, "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) {
1198
parse_err(SYNERR, "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(SYNERR, "missing %c in return address entry.\n", ';');
1207
return;
1208
}
1209
next_char(); // skip the semi-colon
1210
}
1211
else {
1212
parse_err(SYNERR, "Missing %c in return_address entry.\n", '(');
1213
}
1214
}
1215
1216
//------------------------------return_value_parse-----------------------------
1217
char *ADLParser::return_value_parse() {
1218
char *desc = NULL; // String representation of return_value
1219
1220
skipws(); // Skip leading whitespace
1221
if ( (desc = find_cpp_block("return value block")) == NULL ) {
1222
parse_err(SYNERR, "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(SYNERR, "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) {
1241
parse_err(SYNERR, "keyword identifier expected at %c\n", _curchar);
1242
return;
1243
}
1244
1245
skipws();
1246
if ( _curchar != ')' ) { // Check for delimiter
1247
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "\"%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(SYNERR, "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) {
1291
parse_err(SYNERR, "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(SYNERR, "expected '%%{'\n");
1302
return;
1303
}
1304
next_char(); skipws();
1305
1306
char *node_class = get_ident();
1307
if (node_class == NULL) {
1308
parse_err(SYNERR, "expected identifier, found \"%c\"\n", _curchar);
1309
return;
1310
}
1311
1312
skipws();
1313
if (_curchar != ',' && _curchar != '=') {
1314
parse_err(SYNERR, "expected `=`, found '%c'\n", _curchar);
1315
break;
1316
}
1317
next_char(); skipws();
1318
1319
char *pipe_class = get_ident();
1320
if (pipe_class == NULL) {
1321
parse_err(SYNERR, "expected identifier, found \"%c\"\n", _curchar);
1322
return;
1323
}
1324
if (_curchar != ';' ) {
1325
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "\"%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(SYNERR, "expected '%%{'\n");
1358
return;
1359
}
1360
next_char(); skipws();
1361
1362
while (_curchar != '%') {
1363
ident = get_ident();
1364
if (ident == 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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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) {
1519
parse_err(SYNERR, "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(SYNERR, "unknown specifier \"%s\"\n", ident);
1542
}
1543
1544
if ( (_curchar != '%')
1545
|| ( next_char(), (_curchar != '}')) ) {
1546
parse_err(SYNERR, "expected '%%}', found \"%c\"\n", _curchar);
1547
}
1548
next_char(); skipws();
1549
1550
if (pipeline->_maxInstrsPerBundle == 0)
1551
parse_err(SYNERR, "\"max_instructions_per_bundle\" unspecified\n");
1552
if (pipeline->_instrUnitSize == 0 && pipeline->_bundleUnitSize == 0)
1553
parse_err(SYNERR, "\"instruction_unit_size\" and \"bundle_unit_size\" unspecified\n");
1554
if (pipeline->_instrFetchUnitSize == 0)
1555
parse_err(SYNERR, "\"instruction_fetch_unit_size\" unspecified\n");
1556
if (pipeline->_instrFetchUnits == 0)
1557
parse_err(SYNERR, "\"instruction_fetch_units\" unspecified\n");
1558
if (!vsi_seen)
1559
parse_err(SYNERR, "\"variable_size_instruction\" or \"fixed_size_instruction\" unspecified\n");
1560
}
1561
else { // Done with staticly defined parts of instruction definition
1562
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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) {
1600
fprintf(stderr, "resource_parse: identifier: %s\n", ident);
1601
}
1602
}
1603
1604
if (ident == NULL) {
1605
parse_err(SYNERR, "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) {
1617
parse_err(SYNERR, "keyword identifier expected at \"%c\"\n", _curchar);
1618
return;
1619
}
1620
resource = (ResourceForm *) pipeline._resdict[expr];
1621
if (resource == NULL) {
1622
parse_err(SYNERR, "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) {
1633
parse_err(SYNERR, "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) {
1639
parse_err(SYNERR, "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(SYNERR, "\")\" 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(SYNERR, "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) {
1679
parse_err(SYNERR, "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(SYNERR, "\")\" 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) {
1715
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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) {
1743
parse_err(SYNERR, "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(SYNERR, "missing \"(\" in latency definition\n");
1752
return;
1753
}
1754
next_char(); skipws();
1755
if( !isdigit(_curchar) ) {
1756
parse_err(SYNERR, "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(SYNERR, "missing \")\" in latency definition\n");
1763
return;
1764
}
1765
next_char(); skipws();
1766
if (_curchar != ';') {
1767
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "\"(\" 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(SYNERR, "\")\" expected at \"%c\"\n", _curchar);
1833
continue;
1834
}
1835
1836
next_char(); skipws();
1837
if (_curchar != ';') {
1838
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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) {
1897
oper = parm->is_operand();
1898
if (oper == NULL && !parm->is_opclass()) {
1899
parse_err(SYNERR, "operand name expected at %s\n", ident);
1900
continue;
1901
}
1902
1903
if (_curchar != ':') {
1904
parse_err(SYNERR, "\":\" expected at \"%c\"\n", _curchar);
1905
continue;
1906
}
1907
next_char(); skipws();
1908
stage = get_ident();
1909
if (stage == NULL) {
1910
parse_err(SYNERR, "pipeline stage identifier expected at \"%c\"\n", _curchar);
1911
continue;
1912
}
1913
1914
skipws();
1915
if (_curchar != '(') {
1916
parse_err(SYNERR, "\"(\" expected at \"%c\"\n", _curchar);
1917
continue;
1918
}
1919
1920
next_char();
1921
read_or_write = get_ident();
1922
if (read_or_write == NULL) {
1923
parse_err(SYNERR, "\"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(SYNERR, "\"read\" or \"write\" expected at \"%c\"\n", _curchar);
1931
continue;
1932
}
1933
1934
skipws();
1935
if (_curchar != ')') {
1936
parse_err(SYNERR, "\")\" 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(SYNERR, "<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(SYNERR, "\";\" 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) {
1973
int cyclecnt = 1;
1974
if (_curchar != ':') {
1975
parse_err(SYNERR, "\":\" expected at \"%c\"\n", _curchar);
1976
continue;
1977
}
1978
next_char(); skipws();
1979
stage = get_ident();
1980
if (stage == NULL) {
1981
parse_err(SYNERR, "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(SYNERR, "\")\" 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(SYNERR, "\";\" expected at \"%c\"\n", _curchar);
2010
continue;
2011
}
2012
next_char(); skipws();
2013
continue;
2014
}
2015
2016
parse_err(SYNERR, "resource expected at \"%s\"\n", ident);
2017
return;
2018
} while(_curchar != '%');
2019
2020
next_char();
2021
if (_curchar != '}') {
2022
parse_err(SYNERR, "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; // 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) {
2045
parse_err(SYNERR, "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(SYNERR, "expected peepmatch, peepconstraint, or peepreplace for identifier %s.\n", token);
2057
}
2058
skipws();
2059
}
2060
}
2061
else {
2062
parse_err(SYNERR, "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(SYNERR, "missing constraint expression, (...)\n");
2079
return NULL;
2080
}
2081
next_char(); // Skip past '('
2082
2083
// Get constraint function
2084
skipws();
2085
func = get_ident();
2086
if (func == NULL) {
2087
parse_err(SYNERR, "missing function in constraint expression.\n");
2088
return 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(SYNERR, "missing '(' for constraint function's argument.\n");
2096
return NULL;
2097
}
2098
next_char();
2099
2100
// Get it's argument
2101
skipws();
2102
arg = get_ident();
2103
if (arg == NULL) {
2104
parse_err(SYNERR, "missing argument for constraint function %s\n",func);
2105
return NULL;
2106
}
2107
// Check for ')' after argument
2108
skipws();
2109
if (_curchar != ')') {
2110
parse_err(SYNERR, "missing ')' after constraint function argument %s\n",arg);
2111
return NULL;
2112
}
2113
next_char();
2114
} else {
2115
parse_err(SYNERR, "Invalid constraint function %s\n",func);
2116
return NULL;
2117
}
2118
2119
// Check for closing paren and ';'
2120
skipws();
2121
if (_curchar != ')') {
2122
parse_err(SYNERR, "Missing ')' for constraint function %s\n",func);
2123
return NULL;
2124
}
2125
next_char();
2126
skipws();
2127
if (_curchar != ';') {
2128
parse_err(SYNERR, "Missing ';' after constraint.\n");
2129
return 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;
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) {
2152
parse_err(SYNERR, "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;
2160
char *c_conv = NULL;
2161
char *idealtype = NULL;
2162
char *encoding = NULL;
2163
char *concrete = 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) {
2169
parse_err(SYNERR, "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(SYNERR, "invalid value for register calling convention\n");
2175
}
2176
skipws();
2177
if (_curchar != ',') {
2178
parse_err(SYNERR, "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) {
2186
parse_err(SYNERR, "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(SYNERR, "invalid value for register calling convention\n");
2192
}
2193
skipws();
2194
if (_curchar != ',') {
2195
parse_err(SYNERR, "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) {
2204
parse_err(SYNERR, "missing register save type value\n");
2205
return;
2206
}
2207
skipws();
2208
if (_curchar != ',') {
2209
parse_err(SYNERR, "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) {
2218
parse_err(SYNERR, "missing register encoding value\n");
2219
return;
2220
}
2221
trim(encoding);
2222
if (_curchar != ',') {
2223
parse_err(SYNERR, "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) {
2232
parse_err(SYNERR, "missing vm register name value\n");
2233
return;
2234
}
2235
2236
if (_curchar != ')') {
2237
parse_err(SYNERR, "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(SYNERR, "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(stderr,"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) {
2270
parse_err(SYNERR, "missing register class name after 'reg_class'\n");
2271
return;
2272
}
2273
// Debug Stuff
2274
if (_AD._adl_debug >1) fprintf(stderr,"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) {
2287
parse_err(SYNERR, "missing identifier inside reg_class list.\n");
2288
return;
2289
}
2290
RegDef *regDef = _AD._register->getRegDef(rname);
2291
if (!regDef) {
2292
parse_err(SEMERR, "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) {
2311
parse_err(SYNERR, "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(SYNERR, "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) {
2339
parse_err(SYNERR, "missing dynamic register class name after 'reg_class_dynamic'\n");
2340
return;
2341
}
2342
2343
if (_AD._adl_debug > 1) {
2344
fprintf(stdout, "Dynamic Register Class: %s\n", cname);
2345
}
2346
2347
skipws();
2348
if (_curchar != '(') {
2349
parse_err(SYNERR, "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) {
2362
parse_err(SYNERR, "missing class identifier inside reg_class_dynamic list.\n");
2363
return;
2364
}
2365
RegClass* rc = _AD._register->getRegClass(name);
2366
if (rc == NULL) {
2367
parse_err(SEMERR, "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(SYNERR, "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) {
2386
parse_err(SYNERR, "missing code declaration for reg_class_dynamic.\n");
2387
return;
2388
}
2389
reg_class->set_condition_code(code);
2390
} else {
2391
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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) {
2420
parse_err(SYNERR, "missing allocation class name after 'reg_class'\n");
2421
return;
2422
}
2423
// Debug Stuff
2424
if (_AD._adl_debug >1) fprintf(stderr,"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) {
2436
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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;
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;
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 ')'");
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) {
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 ) {
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(SYNERR, "instruction name expected at identifier %s.\n",
2520
token);
2521
return inst_seen;
2522
}
2523
}
2524
else {
2525
parse_err(SYNERR, "missing identifier in peepmatch rule.\n");
2526
return NULL;
2527
}
2528
}
2529
else {
2530
parse_err(SYNERR, "missing identifier in peepmatch rule.\n");
2531
return NULL;
2532
}
2533
2534
} // end while
2535
2536
assert( false, "ShouldNotReachHere();");
2537
return 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(SYNERR, "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 ) {
2563
parse_err(SYNERR, "missing instruction-name at start of peepmatch.\n");
2564
return;
2565
}
2566
2567
if( _curchar != ')' ) {
2568
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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;
2691
char *token = NULL;
2692
2693
skipws();
2694
// Check for open paren
2695
if (_curchar != '(') {
2696
parse_err(SYNERR, "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 || form->is_instruction() == NULL ) {
2708
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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 ) {
2742
parse_err(SYNERR, "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 ')'.");
2754
next_char(); // Skip ')'
2755
2756
skipws();
2757
// Check for end of peepreplace
2758
if( _curchar != ')' ) {
2759
parse_err(SYNERR, "missing ')' at end of peepmatch.\n");
2760
parse_err(SYNERR, "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(SYNERR, "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; // String representation of predicate
2781
2782
skipws(); // Skip leading whitespace
2783
int line = linenum();
2784
if ( (rule = get_paren_expr("pred expression", true)) == NULL ) {
2785
parse_err(SYNERR, "incorrect or missing expression for 'predicate'\n");
2786
return NULL;
2787
}
2788
// Debug Stuff
2789
if (_AD._adl_debug > 1) fprintf(stderr,"Predicate: %s\n", rule);
2790
if (_curchar != ';') {
2791
parse_err(SYNERR, "missing ';' in predicate definition\n");
2792
return 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");
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;
2818
inst._parameters.reset();
2819
while ((param = inst._parameters.iter()) != NULL) {
2820
OpClassForm* opForm = inst._localNames[param]->is_opclass();
2821
assert(opForm != NULL, "sanity");
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) {
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) {
2848
parse_err(SYNERR, "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(SYNERR, "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(stderr, "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(SYNERR, "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; // String representation of encode rule
2981
// identifier is optional.
2982
while (_curchar != ')') {
2983
ec_name = get_ident();
2984
if (ec_name == NULL) {
2985
parse_err(SYNERR, "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) {
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 ) {
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(SYNERR, "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) &&
3029
!ADLParser::is_literal_constant(param) &&
3030
(Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&
3031
((_AD._register == NULL ) || (_AD._register->getRegDef(param) == NULL)) ) {
3032
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "Expected encode parameter before ',' in encoding %s.\n", ec_name);
3059
return;
3060
}
3061
if (_curchar != ')') {
3062
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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) {
3107
parse_err(SYNERR, "Multiple ins_encode sections defined\n");
3108
return;
3109
}
3110
3111
// Debug Stuff
3112
if (_AD._adl_debug > 1) fprintf(stderr,"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(SYNERR, "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; // String representation of encode rule.
3151
// identifier is optional.
3152
if (_curchar != ')') {
3153
ec_name = get_ident();
3154
if (ec_name == NULL) {
3155
parse_err(SYNERR, "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) {
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(SYNERR, "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) &&
3206
!ADLParser::is_literal_constant(param) &&
3207
(Opcode::as_opcode_type(param) == Opcode::NOT_AN_OPCODE) &&
3208
((_AD._register == NULL) || (_AD._register->getRegDef(param) == NULL))) {
3209
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "Expected encode parameter before ',' in postalloc_expand %s.\n", ec_name);
3232
return;
3233
}
3234
if (_curchar != ')') {
3235
parse_err(SYNERR, "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(SYNERR, "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(SYNERR, "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(SYNERR, "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(stderr, "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");
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;
3289
inst._parameters.reset();
3290
while ((param = inst._parameters.iter()) != NULL) {
3291
OpClassForm* opForm = inst._localNames[param]->is_opclass();
3292
assert(opForm != NULL, "sanity");
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) {
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(stderr, "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;
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) {
3393
parse_err(SYNERR, "size of opcode expected at %c\n", _curchar);
3394
return NULL;
3395
}
3396
3397
skipws();
3398
3399
// Check for terminator
3400
if (_curchar != ';') {
3401
parse_err(SYNERR, "missing ';' in ins_attrib definition\n");
3402
return 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) {
3410
fprintf(stderr,"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;
3421
char *secondary = NULL;
3422
char *tertiary = NULL;
3423
3424
char *val = NULL;
3425
Opcode *opcode = NULL;
3426
3427
// Get value of the instruction's opcode
3428
skipws();
3429
if (_curchar != '(') { // Check for parenthesized operand list
3430
parse_err(SYNERR, "missing '(' in expand instruction declaration\n");
3431
return 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 ) {
3438
parse_err(SYNERR, "primary hex opcode expected at %c\n", _curchar);
3439
return 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 ) {
3447
parse_err(SYNERR, "secondary hex opcode expected at %c\n", _curchar);
3448
return 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 ) {
3456
parse_err(SYNERR,"tertiary hex opcode expected at %c\n", _curchar);
3457
return NULL;
3458
}
3459
skipws();
3460
}
3461
}
3462
skipws();
3463
if (_curchar != ')') {
3464
parse_err(SYNERR, "Missing ')' in opcode description\n");
3465
return NULL;
3466
}
3467
}
3468
next_char(); // Skip ')'
3469
skipws();
3470
// Check for terminator
3471
if (_curchar != ';') {
3472
parse_err(SYNERR, "missing ';' in ins_attrib definition\n");
3473
return 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) fprintf(stderr,"primary opcode: %s\n", primary);
3481
if (secondary != NULL) fprintf(stderr,"secondary opcode: %s\n", secondary);
3482
if (tertiary != NULL) fprintf(stderr,"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; // Name of interface class being used
3494
char *iface_code = NULL; // Describe components of this class
3495
3496
// Get interface class name
3497
skipws(); // Skip whitespace
3498
if (_curchar != '(') {
3499
parse_err(SYNERR, "Missing '(' at start of interface description.\n");
3500
return NULL;
3501
}
3502
next_char(); // move past '('
3503
skipws();
3504
iface_name = get_ident();
3505
if (iface_name == NULL) {
3506
parse_err(SYNERR, "missing interface name after 'interface'.\n");
3507
return NULL;
3508
}
3509
skipws();
3510
if (_curchar != ')') {
3511
parse_err(SYNERR, "Missing ')' after name of interface.\n");
3512
return 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;
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(SYNERR, "Extra ';' after defining interface block.\n");
3532
next_char(); // Skip ';'
3533
return 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(stderr,"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;
3559
char *index = NULL;
3560
char *scale = NULL;
3561
char *disp = NULL;
3562
3563
if (_curchar != '%') {
3564
parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n");
3565
return NULL;
3566
}
3567
next_char(); // Skip '%'
3568
if (_curchar != '{') {
3569
parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n");
3570
return NULL;
3571
}
3572
next_char(); // Skip '{'
3573
skipws();
3574
do {
3575
char *field = get_ident();
3576
if (field == NULL) {
3577
parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
3578
return 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(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
3594
return NULL;
3595
}
3596
} while( _curchar != '%' );
3597
next_char(); // Skip '%'
3598
if ( _curchar != '}' ) {
3599
parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n");
3600
return 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(SYNERR, "Missing '%%{' for 'cond_interface' block.\n");
3631
return NULL;
3632
}
3633
next_char(); // Skip '%'
3634
if (_curchar != '{') {
3635
parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n");
3636
return NULL;
3637
}
3638
next_char(); // Skip '{'
3639
skipws();
3640
do {
3641
char *field = get_ident();
3642
if (field == NULL) {
3643
parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
3644
return 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(&not_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(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n");
3672
return NULL;
3673
}
3674
} while( _curchar != '%' );
3675
next_char(); // Skip '%'
3676
if ( _curchar != '}' ) {
3677
parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n");
3678
return 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;
3698
3699
// Get interface field
3700
skipws(); // Skip whitespace
3701
if (_curchar != '(') {
3702
parse_err(SYNERR, "Missing '(' at start of interface field.\n");
3703
return NULL;
3704
}
3705
next_char(); // move past '('
3706
skipws();
3707
if ( _curchar != '0' && _curchar != '$' ) {
3708
parse_err(SYNERR, "missing or invalid interface field contents.\n");
3709
return NULL;
3710
}
3711
iface_field = get_rep_var_ident();
3712
if (iface_field == NULL) {
3713
parse_err(SYNERR, "missing or invalid interface field contents.\n");
3714
return NULL;
3715
}
3716
skipws();
3717
if (format != NULL && _curchar == ',') {
3718
next_char();
3719
skipws();
3720
if (_curchar != '"') {
3721
parse_err(SYNERR, "Missing '\"' in field format .\n");
3722
return 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(SYNERR, "newline in string"); // unimplemented!
3729
next_char();
3730
}
3731
if (_curchar != '"') {
3732
parse_err(SYNERR, "Missing '\"' at end of field format .\n");
3733
return 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(SYNERR, "Missing ')' after interface field.\n");
3745
return NULL;
3746
}
3747
next_char(); // move past ')'
3748
skipws();
3749
if ( _curchar != ';' ) {
3750
parse_err(SYNERR, "Missing ';' at end of interface field.\n");
3751
return 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; // 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; // 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 ) {
3777
parse_err(SYNERR, "invalid construction of match rule\n"
3778
"Missing ';' or invalid '%%{' and '%%}' constructor\n");
3779
return NULL; // No MatchRule to return
3780
}
3781
if (_AD._adl_debug > 1)
3782
if (cnstr) fprintf(stderr,"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;
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; // 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(SYNERR, "Unknown \"%s\" directive in format", ident);
3809
return 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(SYNERR, "missing '\"' at end of format block");
3827
return 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(SYNERR, "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(SYNERR, "non-blank characters between closing '\"' and '%%' in format");
3882
return NULL;
3883
}
3884
} // Done with format description inside
3885
3886
skipws();
3887
// Past format description, at '%'
3888
if ( _curchar != '%' || *(_ptr+1) != '}' ) {
3889
parse_err(SYNERR, "missing '%%}' at end of format block");
3890
return 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(SYNERR, "missing ';' after Format expression");
3897
return NULL;
3898
}
3899
// Debug Stuff
3900
if (_AD._adl_debug > 1) fprintf(stderr,"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;
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(SYNERR, "missing '\"' at end of format block");
3963
return 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(SYNERR, "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(SYNERR, "missing '%%}' at end of format block");
4021
return 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(stderr,"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;
4037
4038
skipws(); // Skip whitespace
4039
if (_curchar != '(') {
4040
parse_err(SYNERR, "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(stderr,"Effect description: %s\n", desc);
4048
if (_curchar != ';') {
4049
parse_err(SYNERR, "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;
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(SYNERR, "missing '%%{' in expand definition\n");
4068
return(NULL);
4069
}
4070
next_char(); // Maintain the invariant
4071
do {
4072
ident = get_ident(); // Grab next identifier
4073
if (ident == NULL) {
4074
parse_err(SYNERR, "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) {
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(SYNERR, "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) {
4101
parse_err(SYNERR, "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) {
4108
parse_err(SYNERR, "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;
4116
skipws();
4117
if (_curchar == '%') { // Need a constructor for the operand
4118
c = find_cpp_block("Operand Constructor");
4119
if (c == NULL) {
4120
parse_err(SYNERR, "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(SYNERR, "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");
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(SYNERR, "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) {
4150
parse_err(SYNERR, "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(SYNERR, "operand name expected at %s\n", ident2);
4156
continue;
4157
}
4158
OperandForm *oper = form2->is_operand();
4159
if (oper == NULL && !form2->is_opclass()) {
4160
parse_err(SYNERR, "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(SYNERR, "missing ')'in expand instruction declaration\n");
4167
continue;
4168
}
4169
next_char();
4170
if (_curchar != ';') {
4171
parse_err(SYNERR, "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(SYNERR, "missing '%%}' in expand rule definition\n");
4186
return(NULL);
4187
}
4188
next_char();
4189
4190
// Debug Stuff
4191
if (_AD._adl_debug > 1) fprintf(stderr,"Expand Rule:\n");
4192
4193
skipws();
4194
return (exp);
4195
}
4196
4197
//------------------------------rewrite_parse----------------------------------
4198
RewriteRule* ADLParser::rewrite_parse(void) {
4199
char* params = NULL;
4200
char* desc = 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) {
4208
parse_err(SYNERR, "missing '(' in rewrite rule\n");
4209
return NULL;
4210
}
4211
// Debug Stuff
4212
if (_AD._adl_debug > 1) fprintf(stderr,"Rewrite parameters: %s\n", params);
4213
4214
// For now, grab entire block;
4215
skipws();
4216
if ( (desc = find_cpp_block("rewrite block")) == NULL ) {
4217
parse_err(SYNERR, "incorrect or missing block for 'rewrite'.\n");
4218
return NULL;
4219
}
4220
// Debug Stuff
4221
if (_AD._adl_debug > 1) fprintf(stderr,"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; // String representation of cost attribute
4231
4232
skipws(); // Skip leading whitespace
4233
if ( (cost = get_paren_expr("attribute")) == NULL ) {
4234
parse_err(SYNERR, "incorrect or missing expression for 'attribute'\n");
4235
return NULL;
4236
}
4237
// Debug Stuff
4238
if (_AD._adl_debug > 1) fprintf(stderr,"Attribute: %s\n", cost);
4239
if (_curchar != ';') {
4240
parse_err(SYNERR, "missing ';' in attribute definition\n");
4241
return NULL;
4242
}
4243
next_char(); // Point after the terminator
4244
4245
skipws();
4246
attrib = new Attribute(ident,cost,INS_ATTR); // 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;
4259
MatchNode *rChild = 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;
4265
4266
next_char(); // advance past '('
4267
4268
// Parse the opcode
4269
token = get_ident(); // Get identifier, opcode
4270
if (token == NULL) {
4271
parse_err(SYNERR, "missing opcode in match expression\n");
4272
return 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; // 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;
4292
if (opcForm != 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;
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(SYNERR, "missing ')' in match expression\n");
4325
return 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;
4345
const char *result = NULL;
4346
const char *token = NULL;
4347
const char *opType = 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;
4357
if (opcForm != NULL) {
4358
opType = opcForm->_ident;
4359
result = opcForm->_ident; // an operand's result matches its type
4360
} else {
4361
parse_err(SYNERR, "undefined operand %s in match rule\n", token);
4362
return NULL;
4363
}
4364
4365
if (opType == NULL) {
4366
parse_err(SYNERR, "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; // Beginning of C++ code block
4384
4385
if (_curchar == '%') { // Encoding is a C++ expression
4386
next_char();
4387
if (_curchar != '{') {
4388
parse_err(SYNERR, "missing '{' in %s \n", description);
4389
return 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(SYNERR, "invalid termination of %s \n", description);
4402
return 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;
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(SYNERR, "too many )'s, did not find %s after %s\n",
4440
stop_chars, desc);
4441
return 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(SYNERR, "newline in string in %s\n", desc);
4454
return 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(SYNERR, "unexpected %%%c in %s\n", _ptr[1], desc);
4461
return NULL;
4462
}
4463
else if (_curchar == '\0') {
4464
parse_err(SYNERR, "unexpected EOF in %s\n", desc);
4465
return 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(SYNERR, "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");
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;
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 ) // Return NULL at EOF.
4521
return 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(SYNERR, "Identifier expected, but found '%s'.", buf);
4541
} else {
4542
parse_err(SYNERR, "Identifier expected, but found '%s'.", start);
4543
}
4544
start = 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) {
4555
const char* def = _AD.get_preproc_def(start);
4556
if (def != 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 && strcmp(def2, def1)) {
4561
def = def2;
4562
const char* def3 = _AD.get_preproc_def(def2);
4563
if (def3 != NULL && strcmp(def3, def2) && strcmp(def3, def1)) {
4564
parse_err(SYNERR, "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 ) {
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;
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),
4604
"expr must be recognizable as a constant");
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(SYNERR, "Replacement variables and field specifiers can not start with '$$$$'");
4636
next_char();
4637
return NULL;
4638
}
4639
4640
// Nil terminate the variable name following the '$'
4641
char *rep_var_name = get_ident();
4642
assert( rep_var_name != NULL,
4643
"Missing identifier after replacement variable indicator '$'");
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;
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(SYNERR, "Replacement variables and field specifiers can not start with '$$$$'");
4674
next_char();
4675
return NULL;
4676
}
4677
4678
// Nil terminate the variable name following the '$'
4679
char *rep_var_name = get_ident();
4680
assert( rep_var_name != NULL,
4681
"Missing identifier after replacement variable indicator '$'");
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) {
4696
parse_err(SYNERR, "missing %s identifier at %c\n", nameDescription, _curchar);
4697
}
4698
else {
4699
if (dict[ident] != NULL) {
4700
parse_err(SYNERR, "duplicate name %s for %s\n", ident, nameDescription);
4701
ident = 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 ) // 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(SYNERR, "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; // relational operator being returned
4753
4754
if( _curline == NULL ) // Return NULL at EOF.
4755
return 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(SYNERR, "relational operator expected at %s\n", _ptr);
4771
}
4772
} else {
4773
parse_err(SYNERR, "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 &parameters, FormDict &operands) {
4786
OpClassForm *opclass = NULL;
4787
char *ident = 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) {
4797
parse_err(SYNERR, "optype identifier expected at %c\n", _curchar);
4798
return;
4799
}
4800
else {
4801
const Form *form = _globalNames[ident];
4802
if( form == NULL ) {
4803
parse_err(SYNERR, "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) && (opc == NULL)) {
4811
parse_err(SYNERR, "identifier %s not operand type\n", ident);
4812
return;
4813
}
4814
opclass = opc;
4815
}
4816
// Debugging Stuff
4817
if (_AD._adl_debug > 1) fprintf(stderr, "\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) {
4821
return;
4822
}
4823
// Parameter names must not be global names.
4824
if( _globalNames[ident] != NULL ) {
4825
parse_err(SYNERR, "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(stderr, "\tOperand Name: %s\n", ident);
4833
skipws();
4834
} while(_curchar == ',');
4835
4836
if (_curchar != ')') parse_err(SYNERR, "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) {
4861
parse_err(SYNERR, "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 ) {
4868
parse_err(SYNERR, "undefined effect type %s\n", ident);
4869
return;
4870
}
4871
else {
4872
if( (eForm = form->is_effect()) == NULL) {
4873
parse_err(SYNERR, "identifier %s not effect type\n", ident);
4874
return;
4875
}
4876
}
4877
}
4878
// Debugging Stuff
4879
if (_AD._adl_debug > 1) fprintf(stderr, "\tEffect Type: %s\t", ident);
4880
skipws();
4881
if (eForm->is(Component::CALL)) {
4882
if (_AD._adl_debug > 1) fprintf(stderr, "\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) {
4887
parse_err(SYNERR, "missing operand identifier in effect list\n");
4888
return;
4889
}
4890
const Form *form = operands[ident];
4891
opForm = form ? form->is_operand() : NULL;
4892
if( opForm == NULL ) {
4893
if( form && form->is_opclass() ) {
4894
const char* cname = form->is_opclass()->_ident;
4895
parse_err(SYNERR, "operand classes are illegal in effect lists (found %s %s)\n", cname, ident);
4896
} else {
4897
parse_err(SYNERR, "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(stderr, "\tOperand Name: %s\n", ident);
4905
}
4906
skipws();
4907
} while(_curchar == ',');
4908
4909
if (_curchar != ')') parse_err(SYNERR, "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;
4922
if (_curchar == '"') {
4923
next_char(); // Move past the initial '"'
4924
file = _ptr;
4925
while (true) {
4926
if (_curchar == '\n') {
4927
parse_err(SYNERR, "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)
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(SYNERR, "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);
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);
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);
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(stderr, "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),
5010
"Must be able to find which line we are in" );
5011
5012
for (char *s = _curline; s < _ptr; s++) {
5013
if (*s > ' ') {
5014
parse_err(SYNERR, "'%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(SYNERR, "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");
5052
ensure_start_of_line();
5053
next_char();
5054
skipws_no_preproc();
5055
char* start_ident = _ptr;
5056
char* ident = (_curchar == '\n') ? NULL : get_ident_no_preproc();
5057
if (ident == NULL) {
5058
parse_err(SYNERR, "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);
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(SYNERR, "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(SYNERR, "no space allowed after # in #define or #undef");
5085
assert(_curchar == '#', "no space allowed after # in #define or #undef");
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(SYNERR, "unimplemented: comment token in a funny place");
5111
}
5112
}
5113
while(_curline != 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) { // check for end of file
5128
parse_err(SYNERR, "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");
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(SYNERR, "newline in string");
5159
break;
5160
}
5161
}
5162
next = _ptr + 1;
5163
}
5164
else { ++_ptr; ++next; }
5165
}
5166
if( _curline != 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(WARN, "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");
5259
const char* eol = strchr(cp, '\n');
5260
assert(eol != NULL, "must find end of line");
5261
if (eol == 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 || str2 == 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
}
5317
5318