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