ctf: Fix API inconsistencies
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / internal / ctf / core / event / metadata / IOStructGen.java
CommitLineData
866e5b51
FC
1/*******************************************************************************
2 * Copyright (c) 2011-2012 Ericsson, Ecole Polytechnique de Montreal and others
3 *
4 * All rights reserved. This program and the accompanying materials are made
5 * available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors: Matthew Khouzam - Initial Design and Grammar
10 * Contributors: Francis Giraldeau - Initial API and implementation
11 *******************************************************************************/
12
ce2388e0 13package org.eclipse.linuxtools.internal.ctf.core.event.metadata;
866e5b51
FC
14
15import java.io.FileNotFoundException;
16import java.io.IOException;
17import java.io.UnsupportedEncodingException;
18import java.nio.ByteOrder;
19import java.util.ArrayList;
20import java.util.Collections;
866e5b51
FC
21import java.util.LinkedList;
22import java.util.List;
866e5b51
FC
23import java.util.UUID;
24
25import org.antlr.runtime.tree.CommonTree;
866e5b51
FC
26import org.eclipse.linuxtools.ctf.core.event.CTFClock;
27import org.eclipse.linuxtools.ctf.core.event.EventDeclaration;
866e5b51
FC
28import org.eclipse.linuxtools.ctf.core.event.types.ArrayDeclaration;
29import org.eclipse.linuxtools.ctf.core.event.types.Encoding;
30import org.eclipse.linuxtools.ctf.core.event.types.EnumDeclaration;
53047a66 31import org.eclipse.linuxtools.ctf.core.event.types.FloatDeclaration;
866e5b51
FC
32import org.eclipse.linuxtools.ctf.core.event.types.IDeclaration;
33import org.eclipse.linuxtools.ctf.core.event.types.IntegerDeclaration;
34import org.eclipse.linuxtools.ctf.core.event.types.SequenceDeclaration;
35import org.eclipse.linuxtools.ctf.core.event.types.StringDeclaration;
36import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration;
37import org.eclipse.linuxtools.ctf.core.event.types.VariantDeclaration;
38import org.eclipse.linuxtools.ctf.core.trace.CTFTrace;
486efb2e 39import org.eclipse.linuxtools.ctf.core.trace.Stream;
866e5b51 40import org.eclipse.linuxtools.ctf.parser.CTFParser;
ce2388e0 41import org.eclipse.linuxtools.internal.ctf.core.event.metadata.exceptions.ParseException;
866e5b51 42
866e5b51 43/**
251274dd 44 * IOStructGen
866e5b51 45 */
866e5b51
FC
46public class IOStructGen {
47
48 // ------------------------------------------------------------------------
49 // Attributes
50 // ------------------------------------------------------------------------
51
52 static private final boolean DEBUG_ = false;
53
54 /**
55 * The trace
56 */
57 private final CTFTrace trace;
58 private final CommonTree tree;
59
60 /**
61 * The current declaration scope.
62 */
63 private DeclarationScope scope = null;
64
65 // ------------------------------------------------------------------------
66 // Constructor
67 // ------------------------------------------------------------------------
68
9ac2eb62
MK
69 /**
70 * Constuctor
be6df2d8
AM
71 *
72 * @param tree
73 * the tree (ANTLR generated) with the parsed TSDL data.
74 * @param trace
75 * the trace containing the places to put all the read metadata
9ac2eb62 76 */
866e5b51
FC
77 public IOStructGen(CommonTree tree, CTFTrace trace) {
78 this.trace = trace;
79 this.tree = tree;
80 }
81
9ac2eb62
MK
82 /**
83 * Parse the tree and populate the trace defined in the constructor.
be6df2d8 84 *
9ac2eb62 85 * @throws ParseException
be6df2d8 86 * If there was a problem parsing the metadata
9ac2eb62 87 */
866e5b51
FC
88 public void generate() throws ParseException {
89 parseRoot(tree);
90 }
91
92 // ------------------------------------------------------------------------
93 // Operations
94 // ------------------------------------------------------------------------
95
96 /**
97 * Parse the root node.
98 *
99 * @param root
100 * A ROOT node.
101 * @throws ParseException
102 */
103 private void parseRoot(CommonTree root) throws ParseException {
866e5b51
FC
104
105 List<CommonTree> children = root.getChildren();
866e5b51
FC
106 java.io.FileOutputStream fos = null;
107 java.io.OutputStreamWriter out = null;
108 if (DEBUG_) {
109 try {
110 fos = new java.io.FileOutputStream("/tmp/astInfo.txt"); //$NON-NLS-1$
111 out = new java.io.OutputStreamWriter(fos, "UTF-8"); //$NON-NLS-1$
112 } catch (FileNotFoundException e) {
113 e.printStackTrace();
114 return;
115 } catch (UnsupportedEncodingException e) {
116 e.printStackTrace();
117 return;
118 }
119 }
120
121 CommonTree traceNode = null;
122 List<CommonTree> streams = new ArrayList<CommonTree>();
123 List<CommonTree> events = new ArrayList<CommonTree>();
124 List<CommonTree> declarations = new ArrayList<CommonTree>();
125 List<CommonTree> environments = new ArrayList<CommonTree>();
126 List<CommonTree> clocks = new ArrayList<CommonTree>();
4c9d2941 127 List<CommonTree> callsites = new ArrayList<CommonTree>();
866e5b51
FC
128 /* Create a new declaration scope with no parent. */
129 pushScope();
130
131 try {
132 for (CommonTree child : children) {
4c9d2941 133 final int type = child.getType();
866e5b51
FC
134 if (DEBUG_) {
135 out.write(child.toString()
4c9d2941 136 + " -> " + type + '\n'); //$NON-NLS-1$
866e5b51 137 }
4c9d2941 138 switch (type) {
866e5b51
FC
139 case CTFParser.DECLARATION:
140 declarations.add(child);
141 break;
142 case CTFParser.TRACE:
143 if (traceNode != null) {
144 throw new ParseException(
145 "Only one trace block is allowed"); //$NON-NLS-1$
146 }
147 traceNode = child;
148 break;
149 case CTFParser.STREAM:
150 streams.add(child);
151 break;
152 case CTFParser.EVENT:
153 events.add(child);
154 break;
155 case CTFParser.CLOCK:
156 clocks.add(child);
157 break;
158 case CTFParser.ENV:
159 environments.add(child);
160 break;
4c9d2941
MK
161 case CTFParser.CALLSITE:
162 callsites.add(child);
163 break;
866e5b51
FC
164 default:
165 childTypeError(child);
166 }
167 }
866e5b51
FC
168 if (DEBUG_) {
169 out.write("Declarations\n"); //$NON-NLS-1$
170 }
171 for (CommonTree decl : declarations) {
172 if (DEBUG_) {
173 out.write(decl.toString() + '\n');
174 }
175 parseRootDeclaration(decl);
176 }
866e5b51
FC
177 if (traceNode == null) {
178 throw new ParseException("Missing trace block"); //$NON-NLS-1$
179 }
180
181 parseTrace(traceNode);
182
72dbc4ac
MK
183 if (DEBUG_) {
184 out.write("Environments\n"); //$NON-NLS-1$
185 }
186 for (CommonTree environment : environments) {
187 parseEnvironment(environment);
188 }
189 if (DEBUG_) {
190 out.write("Clocks\n"); //$NON-NLS-1$
191 }
192 for (CommonTree clock : clocks) {
193 parseClock(clock);
194 }
4c9d2941
MK
195 if (DEBUG_) {
196 out.write("Callsites\n"); //$NON-NLS-1$
197 }
198 for (CommonTree callsite : callsites) {
199 parseCallsite(callsite);
200 }
72dbc4ac 201
866e5b51
FC
202 if (DEBUG_) {
203 out.write("Streams\n"); //$NON-NLS-1$
204 }
205 if (streams.size() > 0) {
206 for (CommonTree stream : streams) {
207 if (DEBUG_) {
208 try {
209 out.write(stream.toString() + '\n');
210 } catch (IOException e) {
211 e.printStackTrace();
212 }
213 }
214 parseStream(stream);
215 }
216 } else {
217 /* Add an empty stream that will have a null id */
218 trace.addStream(new Stream(trace));
219 }
220
221 if (DEBUG_) {
222 out.write("Events\n"); //$NON-NLS-1$
223 }
224 for (CommonTree event : events) {
225 parseEvent(event);
866e5b51 226 if (DEBUG_) {
32ede2ec
MK
227 CommonTree name = (CommonTree) event.getChild(0).getChild(1).getChild(0).getChild(0);
228 CommonTree id = (CommonTree) event.getChild(1).getChild(1).getChild(0).getChild(0);
866e5b51
FC
229 out.write("Name = " + name + " Id = " + id + '\n'); //$NON-NLS-1$ //$NON-NLS-2$
230 }
231 }
232
233 if (DEBUG_) {
234 out.close();
235 fos.close();
236 }
237 } catch (IOException e) {
238 e.printStackTrace();
239 }
240 popScope();
241 }
242
4c9d2941
MK
243 private void parseCallsite(CommonTree callsite) {
244
245 List<CommonTree> children = callsite.getChildren();
246 String name = null;
247 String func_name = null;
248 long line_number = -1;
249 long ip = -1;
250 String file_name = null;
251
252 for (CommonTree child : children) {
253 String left;
254 /* this is a regex to find the leading and trailing quotes*/
255 final String regex = "^\"|\"$"; //$NON-NLS-1$
256 /* this is to replace the previous quotes with nothing... effectively deleting them */
257 final String nullString = ""; //$NON-NLS-1$
258 left = child.getChild(0).getChild(0).getChild(0).getText();
259 if (left.equals("name")) { //$NON-NLS-1$
260 name = child.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex, nullString);
261 } else if (left.equals("func")) { //$NON-NLS-1$
262 func_name = child.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex, nullString);
263 } else if (left.equals("ip")) { //$NON-NLS-1$
264 ip = Long.parseLong(child.getChild(1).getChild(0).getChild(0).getText().substring(2),16); // trim the 0x
265 } else if (left.equals("file")) { //$NON-NLS-1$
266 file_name = child.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex, nullString);
267 } else if (left.equals("line")) { //$NON-NLS-1$
268 line_number = Long.parseLong(child.getChild(1).getChild(0).getChild(0).getText());
269 }
270 }
271 trace.addCallsite(name, func_name, ip,file_name, line_number);
272 }
273
866e5b51
FC
274 private void parseEnvironment(CommonTree environment) {
275 List<CommonTree> children = environment.getChildren();
276 for (CommonTree child : children) {
277 String left;
278 String right;
279 left = child.getChild(0).getChild(0).getChild(0).getText();
280 right = child.getChild(1).getChild(0).getChild(0).getText();
281 trace.addEnvironmentVar(left, right);
282 }
283 }
284
285 private void parseClock(CommonTree clock) {
286 List<CommonTree> children = clock.getChildren();
287 CTFClock ctfClock = new CTFClock();
288 for (CommonTree child : children) {
72dbc4ac 289 final String key = child.getChild(0).getChild(0).getChild(0).getText();
866e5b51
FC
290 final CommonTree value = (CommonTree) child.getChild(1).getChild(0).getChild(0);
291 final int type = value.getType();
292 switch (type) {
293 case CTFParser.INTEGER:
294 case CTFParser.DECIMAL_LITERAL:
284fdee8 295 /*
32ede2ec
MK
296 * Not a pretty hack, this is to make sure that there is no
297 * number overflow due to 63 bit integers. The offset should
298 * only really be an issue in the year 2262. the tracer in C/ASM
299 * can write an offset in an unsigned 64 bit long. In java, the
300 * last bit, being set to 1 will be read as a negative number,
301 * but since it is too big a positive it will throw an
302 * exception. this will happen in 2^63 ns from 1970. Therefore
303 * 293 years from 1970
284fdee8 304 */
866e5b51 305 Long numValue;
32ede2ec 306 try {
866e5b51 307 numValue = Long.parseLong(value.getText());
32ede2ec 308 } catch (Exception e) {
866e5b51
FC
309 numValue = 1330938566783103277L;
310 }
311 ctfClock.addAttribute(key, numValue);
312 break;
313 default:
314 ctfClock.addAttribute(key, value.getText());
315 }
316
317 }
318 String NameValue = ctfClock.getName();
319 trace.addClock(NameValue, ctfClock);
320 }
321
322 private void parseTrace(CommonTree traceNode) throws ParseException {
866e5b51
FC
323
324 List<CommonTree> children = traceNode.getChildren();
325 if (children == null) {
326 throw new ParseException("Trace block is empty"); //$NON-NLS-1$
327 }
328
329 pushScope();
330
331 for (CommonTree child : children) {
332 switch (child.getType()) {
333 case CTFParser.TYPEALIAS:
334 parseTypealias(child);
335 break;
336 case CTFParser.TYPEDEF:
337 parseTypedef(child);
338 break;
339 case CTFParser.CTF_EXPRESSION_TYPE:
340 case CTFParser.CTF_EXPRESSION_VAL:
341 parseTraceDeclaration(child);
342 break;
343 default:
344 childTypeError(child);
345 break;
346 }
347 }
348
349 /*
350 * If trace byte order was not specified and not using packet based
351 * metadata
352 */
353 if (trace.getByteOrder() == null) {
354 throw new ParseException("Trace byte order not set"); //$NON-NLS-1$
355 }
356
357 popScope();
358 }
359
360 private void parseTraceDeclaration(CommonTree traceDecl)
361 throws ParseException {
866e5b51
FC
362
363 /* There should be a left and right */
866e5b51
FC
364
365 CommonTree leftNode = (CommonTree) traceDecl.getChild(0);
866e5b51 366 CommonTree rightNode = (CommonTree) traceDecl.getChild(1);
866e5b51
FC
367
368 List<CommonTree> leftStrings = leftNode.getChildren();
866e5b51
FC
369
370 if (!isUnaryString(leftStrings.get(0))) {
371 throw new ParseException(
372 "Left side of CTF assignment must be a string"); //$NON-NLS-1$
373 }
374
375 String left = concatenateUnaryStrings(leftStrings);
376
07002e0a 377 if (left.equals(CTFStrings.MAJOR)) {
866e5b51
FC
378 if (trace.majortIsSet()) {
379 throw new ParseException("major is already set"); //$NON-NLS-1$
380 }
381
382 trace.setMajor(getMajorOrMinor(rightNode));
07002e0a 383 } else if (left.equals(CTFStrings.MINOR)) {
866e5b51
FC
384 if (trace.minorIsSet()) {
385 throw new ParseException("minor is already set"); //$NON-NLS-1$
386 }
387
388 trace.setMinor(getMajorOrMinor(rightNode));
07002e0a 389 } else if (left.equals(CTFStrings.UUID_STRING)) {
866e5b51
FC
390 UUID uuid = getUUID(rightNode);
391
392 /*
393 * If uuid was already set by a metadata packet, compare it to see
394 * if it matches
395 */
396 if (trace.UUIDIsSet()) {
397 if (trace.getUUID().compareTo(uuid) != 0) {
398 throw new ParseException("UUID mismatch. Packet says " //$NON-NLS-1$
399 + trace.getUUID() + " but metadata says " + uuid); //$NON-NLS-1$
400 }
401 } else {
402 trace.setUUID(uuid);
403 }
404
07002e0a 405 } else if (left.equals(CTFStrings.BYTE_ORDER)) {
866e5b51
FC
406 ByteOrder byteOrder = getByteOrder(rightNode);
407
408 /*
409 * If byte order was already set by a metadata packet, compare it to
410 * see if it matches
411 */
412 if (trace.getByteOrder() != null) {
413 if (trace.getByteOrder() != byteOrder) {
414 throw new ParseException(
415 "Endianness mismatch. Magic number says " //$NON-NLS-1$
416 + trace.getByteOrder()
417 + " but metadata says " + byteOrder); //$NON-NLS-1$
418 }
419 } else {
420 trace.setByteOrder(byteOrder);
72dbc4ac
MK
421 final DeclarationScope parentScope = scope.getParentScope();
422 String types[] = parentScope.getTypeNames();
423
424 for (String type : types) {
425 IDeclaration d = parentScope.lookupType(type);
426 if (d instanceof IntegerDeclaration) {
427 addByteOrder(byteOrder, parentScope, type, (IntegerDeclaration) d);
428 } else if (d instanceof StructDeclaration) {
429 setAlign(parentScope, (StructDeclaration) d, byteOrder);
430 }
431 }
866e5b51 432 }
07002e0a 433 } else if (left.equals(CTFStrings.PACKET_HEADER)) {
866e5b51
FC
434 if (trace.packetHeaderIsSet()) {
435 throw new ParseException("packet.header already defined"); //$NON-NLS-1$
436 }
437
438 CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
439
440 if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
441 throw new ParseException(
442 "packet.header expects a type specifier"); //$NON-NLS-1$
443 }
444
445 IDeclaration packetHeaderDecl = parseTypeSpecifierList(
446 typeSpecifier, null);
447
448 if (!(packetHeaderDecl instanceof StructDeclaration)) {
449 throw new ParseException("packet.header expects a struct"); //$NON-NLS-1$
450 }
451
452 trace.setPacketHeader((StructDeclaration) packetHeaderDecl);
453 } else {
454 throw new ParseException("Unknown trace attribute : " + left); //$NON-NLS-1$
455 }
456 }
457
72dbc4ac
MK
458 private static void addByteOrder(ByteOrder byteOrder,
459 final DeclarationScope parentScope, String name,
460 IntegerDeclaration decl) throws ParseException {
461
462 if (decl.getByteOrder() == null) {
463 IntegerDeclaration newI;
464 newI = new IntegerDeclaration(decl.getLength(), decl.isSigned(),
465 decl.getBase(), byteOrder, decl.getEncoding(),
466 decl.getClock(), decl.getAlignment());
467 parentScope.replaceType(name, newI);
468 }
469 }
470
471 private void setAlign(DeclarationScope parentScope, StructDeclaration sd,
472 ByteOrder byteOrder) throws ParseException {
473
474 for (String s : sd.getFieldsList()) {
475 IDeclaration d = sd.getFields().get(s);
476
477 if (d instanceof StructDeclaration) {
478 setAlign(parentScope, (StructDeclaration) d, byteOrder);
479
480 } else if (d instanceof VariantDeclaration) {
481 setAlign(parentScope, (VariantDeclaration) d, byteOrder);
482
483 } else if (d instanceof IntegerDeclaration) {
484 IntegerDeclaration decl = (IntegerDeclaration) d;
485 if (decl.getByteOrder() == null) {
486 IntegerDeclaration newI;
487 newI = new IntegerDeclaration(decl.getLength(),
488 decl.isSigned(), decl.getBase(), byteOrder,
489 decl.getEncoding(), decl.getClock(),
490 decl.getAlignment());
491 sd.getFields().put(s, newI);
492 }
493 }
494 }
495 }
496
497 private void setAlign(DeclarationScope parentScope, VariantDeclaration vd,
498 ByteOrder byteOrder) throws ParseException {
499
500 for (String s : vd.getFields().keySet()) {
501 IDeclaration d = vd.getFields().get(s);
502
503 if (d instanceof StructDeclaration) {
504 setAlign(parentScope, (StructDeclaration) d, byteOrder);
505
506 } else if (d instanceof IntegerDeclaration) {
507 IntegerDeclaration decl = (IntegerDeclaration) d;
508 IntegerDeclaration newI;
509 newI = new IntegerDeclaration(decl.getLength(),
510 decl.isSigned(), decl.getBase(), byteOrder,
511 decl.getEncoding(), decl.getClock(),
512 decl.getAlignment());
513 vd.getFields().put(s, newI);
514 }
515 }
516 }
517
866e5b51 518 private void parseStream(CommonTree streamNode) throws ParseException {
866e5b51
FC
519
520 Stream stream = new Stream(trace);
521
522 List<CommonTree> children = streamNode.getChildren();
523 if (children == null) {
524 throw new ParseException("Empty stream block"); //$NON-NLS-1$
525 }
526
527 pushScope();
528
529 for (CommonTree child : children) {
530 switch (child.getType()) {
531 case CTFParser.TYPEALIAS:
532 parseTypealias(child);
533 break;
534 case CTFParser.TYPEDEF:
535 parseTypedef(child);
536 break;
537 case CTFParser.CTF_EXPRESSION_TYPE:
538 case CTFParser.CTF_EXPRESSION_VAL:
539 parseStreamDeclaration(child, stream);
540 break;
541 default:
542 childTypeError(child);
543 break;
544 }
545 }
546
9ac2eb62 547 if (stream.isIdSet()) {
866e5b51 548 if (!trace.packetHeaderIsSet()
07002e0a 549 || !trace.getPacketHeader().hasField(CTFStrings.STREAM_ID)) {
866e5b51
FC
550 throw new ParseException(
551 "Stream has an ID, but there is no stream_id field in packet header."); //$NON-NLS-1$
552 }
553 }
554
555 trace.addStream(stream);
556
557 popScope();
558 }
559
560 private void parseStreamDeclaration(CommonTree streamDecl, Stream stream)
561 throws ParseException {
866e5b51
FC
562
563 /* There should be a left and right */
866e5b51
FC
564
565 CommonTree leftNode = (CommonTree) streamDecl.getChild(0);
866e5b51 566 CommonTree rightNode = (CommonTree) streamDecl.getChild(1);
866e5b51
FC
567
568 List<CommonTree> leftStrings = leftNode.getChildren();
866e5b51
FC
569
570 if (!isUnaryString(leftStrings.get(0))) {
571 throw new ParseException(
572 "Left side of CTF assignment must be a string"); //$NON-NLS-1$
573 }
574
575 String left = concatenateUnaryStrings(leftStrings);
576
07002e0a 577 if (left.equals(CTFStrings.ID)) {
9ac2eb62 578 if (stream.isIdSet()) {
866e5b51
FC
579 throw new ParseException("stream id already defined"); //$NON-NLS-1$
580 }
581
582 long streamID = getStreamID(rightNode);
583
584 stream.setId(streamID);
07002e0a 585 } else if (left.equals(CTFStrings.EVENT_HEADER)) {
9ac2eb62 586 if (stream.isEventHeaderSet()) {
866e5b51
FC
587 throw new ParseException("event.header already defined"); //$NON-NLS-1$
588 }
589
590 CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
591
592 if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
593 throw new ParseException(
594 "event.header expects a type specifier"); //$NON-NLS-1$
595 }
596
597 IDeclaration eventHeaderDecl = parseTypeSpecifierList(
598 typeSpecifier, null);
599
600 if (!(eventHeaderDecl instanceof StructDeclaration)) {
601 throw new ParseException("event.header expects a struct"); //$NON-NLS-1$
602 }
603
604 stream.setEventHeader((StructDeclaration) eventHeaderDecl);
07002e0a 605 } else if (left.equals(CTFStrings.EVENT_CONTEXT)) {
9ac2eb62 606 if (stream.isEventContextSet()) {
866e5b51
FC
607 throw new ParseException("event.context already defined"); //$NON-NLS-1$
608 }
609
610 CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
611
612 if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
613 throw new ParseException(
614 "event.context expects a type specifier"); //$NON-NLS-1$
615 }
616
617 IDeclaration eventContextDecl = parseTypeSpecifierList(
618 typeSpecifier, null);
619
620 if (!(eventContextDecl instanceof StructDeclaration)) {
621 throw new ParseException("event.context expects a struct"); //$NON-NLS-1$
622 }
623
624 stream.setEventContext((StructDeclaration) eventContextDecl);
07002e0a 625 } else if (left.equals(CTFStrings.PACKET_CONTEXT)) {
9ac2eb62 626 if (stream.isPacketContextSet()) {
866e5b51
FC
627 throw new ParseException("packet.context already defined"); //$NON-NLS-1$
628 }
629
630 CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
631
632 if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
633 throw new ParseException(
634 "packet.context expects a type specifier"); //$NON-NLS-1$
635 }
636
637 IDeclaration packetContextDecl = parseTypeSpecifierList(
638 typeSpecifier, null);
639
640 if (!(packetContextDecl instanceof StructDeclaration)) {
641 throw new ParseException("packet.context expects a struct"); //$NON-NLS-1$
642 }
643
644 stream.setPacketContext((StructDeclaration) packetContextDecl);
645 } else {
646 throw new ParseException("Unknown stream attribute : " + left); //$NON-NLS-1$
647 }
648 }
649
650 private void parseEvent(CommonTree eventNode) throws ParseException {
866e5b51
FC
651
652 List<CommonTree> children = eventNode.getChildren();
653 if (children == null) {
654 throw new ParseException("Empty event block"); //$NON-NLS-1$
655 }
656
657 EventDeclaration event = new EventDeclaration();
658
659 pushScope();
660
661 for (CommonTree child : children) {
662 switch (child.getType()) {
663 case CTFParser.TYPEALIAS:
664 parseTypealias(child);
665 break;
666 case CTFParser.TYPEDEF:
667 parseTypedef(child);
668 break;
669 case CTFParser.CTF_EXPRESSION_TYPE:
670 case CTFParser.CTF_EXPRESSION_VAL:
671 parseEventDeclaration(child, event);
672 break;
673 default:
674 childTypeError(child);
675 break;
676 }
677 }
678
679 if (!event.nameIsSet()) {
680 throw new ParseException("Event name not set"); //$NON-NLS-1$
681 }
682
683 /*
684 * If the event did not specify a stream, then the trace must be single
685 * stream
686 */
687 if (!event.streamIsSet()) {
688 if (trace.nbStreams() > 1) {
689 throw new ParseException(
690 "Event without stream_id with more than one stream"); //$NON-NLS-1$
691 }
692
693 /*
694 * If the event did not specify a stream, the only existing stream
695 * must not have an id. Note: That behavior could be changed, it
696 * could be possible to just get the only existing stream, whatever
697 * is its id.
698 */
699 Stream stream = trace.getStream(null);
700
701 if (stream != null) {
702 event.setStream(stream);
703 } else {
704 throw new ParseException(
705 "Event without stream_id, but there is no stream without id"); //$NON-NLS-1$
706 }
707 }
708
709 /*
710 * Add the event to the stream.
711 */
712 event.getStream().addEvent(event);
713
714 popScope();
715 }
716
717 private void parseEventDeclaration(CommonTree eventDecl,
718 EventDeclaration event) throws ParseException {
866e5b51
FC
719
720 /* There should be a left and right */
866e5b51
FC
721
722 CommonTree leftNode = (CommonTree) eventDecl.getChild(0);
866e5b51 723 CommonTree rightNode = (CommonTree) eventDecl.getChild(1);
866e5b51
FC
724
725 List<CommonTree> leftStrings = leftNode.getChildren();
866e5b51
FC
726
727 if (!isUnaryString(leftStrings.get(0))) {
728 throw new ParseException(
729 "Left side of CTF assignment must be a string"); //$NON-NLS-1$
730 }
731
732 String left = concatenateUnaryStrings(leftStrings);
733
07002e0a 734 if (left.equals(CTFStrings.NAME2)) {
866e5b51
FC
735 if (event.nameIsSet()) {
736 throw new ParseException("name already defined"); //$NON-NLS-1$
737 }
738
739 String name = getEventName(rightNode);
740
741 event.setName(name);
07002e0a 742 } else if (left.equals(CTFStrings.ID)) {
866e5b51
FC
743 if (event.idIsSet()) {
744 throw new ParseException("id already defined"); //$NON-NLS-1$
745 }
746
747 long id = getEventID(rightNode);
748
749 event.setId(id);
07002e0a 750 } else if (left.equals(CTFStrings.STREAM_ID)) {
866e5b51
FC
751 if (event.streamIsSet()) {
752 throw new ParseException("stream id already defined"); //$NON-NLS-1$
753 }
754
755 long streamId = getStreamID(rightNode);
756
757 Stream stream = trace.getStream(streamId);
758
759 if (stream == null) {
760 throw new ParseException("Stream " + streamId + " not found"); //$NON-NLS-1$ //$NON-NLS-2$
761 }
762
763 event.setStream(stream);
07002e0a 764 } else if (left.equals(CTFStrings.CONTEXT)) {
866e5b51
FC
765 if (event.contextIsSet()) {
766 throw new ParseException("context already defined"); //$NON-NLS-1$
767 }
768
769 CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
770
771 if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
772 throw new ParseException("context expects a type specifier"); //$NON-NLS-1$
773 }
774
775 IDeclaration contextDecl = parseTypeSpecifierList(typeSpecifier,
776 null);
777
778 if (!(contextDecl instanceof StructDeclaration)) {
779 throw new ParseException("context expects a struct"); //$NON-NLS-1$
780 }
781
782 event.setContext((StructDeclaration) contextDecl);
07002e0a 783 } else if (left.equals(CTFStrings.FIELDS_STRING)) {
866e5b51
FC
784 if (event.fieldsIsSet()) {
785 throw new ParseException("fields already defined"); //$NON-NLS-1$
786 }
787
788 CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0);
789
790 if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) {
791 throw new ParseException("fields expects a type specifier"); //$NON-NLS-1$
792 }
793
13be1a8f
AM
794 IDeclaration fieldsDecl;
795 fieldsDecl = parseTypeSpecifierList(typeSpecifier, null);
866e5b51
FC
796
797 if (!(fieldsDecl instanceof StructDeclaration)) {
798 throw new ParseException("fields expects a struct"); //$NON-NLS-1$
799 }
800 /*
32ede2ec
MK
801 * The underscores in the event names. These underscores were added
802 * by the LTTng tracer.
866e5b51 803 */
91847dfc 804 final StructDeclaration fields = (StructDeclaration) fieldsDecl;
866e5b51 805 event.setFields(fields);
32ede2ec
MK
806 } else if (left.equals(CTFStrings.LOGLEVEL2)) {
807 long logLevel = parseUnaryInteger((CommonTree) rightNode.getChild(0));
53047a66 808 event.setLogLevel(logLevel);
866e5b51 809 } else {
7e659abc
AM
810 /* Unknown event attribute, we'll simply ignore it */
811 // FIXME log this?
866e5b51
FC
812 }
813 }
814
815 /**
816 * Parses a declaration at the root level.
817 *
818 * @param declaration
819 * The declaration subtree.
820 * @throws ParseException
821 */
822 private void parseRootDeclaration(CommonTree declaration)
823 throws ParseException {
866e5b51
FC
824
825 List<CommonTree> children = declaration.getChildren();
866e5b51
FC
826
827 for (CommonTree child : children) {
828 switch (child.getType()) {
829 case CTFParser.TYPEDEF:
830 parseTypedef(child);
831 break;
832 case CTFParser.TYPEALIAS:
833 parseTypealias(child);
834 break;
835 case CTFParser.TYPE_SPECIFIER_LIST:
836 parseTypeSpecifierList(child, null);
837 break;
838 default:
839 childTypeError(child);
840 }
841 }
842 }
843
844 /**
845 * Parses a typealias node. It parses the target, the alias, and registers
846 * the type in the current scope.
847 *
848 * @param typealias
849 * A TYPEALIAS node.
850 * @throws ParseException
851 */
852 private void parseTypealias(CommonTree typealias) throws ParseException {
866e5b51
FC
853
854 List<CommonTree> children = typealias.getChildren();
866e5b51
FC
855
856 CommonTree target = null;
857 CommonTree alias = null;
858
859 for (CommonTree child : children) {
860 switch (child.getType()) {
861 case CTFParser.TYPEALIAS_TARGET:
866e5b51
FC
862 target = child;
863 break;
864 case CTFParser.TYPEALIAS_ALIAS:
866e5b51
FC
865 alias = child;
866 break;
867 default:
868 childTypeError(child);
869 break;
870 }
871 }
872
866e5b51
FC
873
874 IDeclaration targetDeclaration = parseTypealiasTarget(target);
875
876 if (targetDeclaration instanceof VariantDeclaration) {
877 if (((VariantDeclaration) targetDeclaration).isTagged()) {
878 throw new ParseException(
879 "Typealias of untagged variant is not permitted"); //$NON-NLS-1$
880 }
881 }
882
883 String aliasString = parseTypealiasAlias(alias);
884
885 getCurrentScope().registerType(aliasString, targetDeclaration);
886 }
887
888 /**
889 * Parses the target part of a typealias and gets the corresponding
890 * declaration.
891 *
892 * @param target
893 * A TYPEALIAS_TARGET node.
894 * @return The corresponding declaration.
895 * @throws ParseException
896 */
897 private IDeclaration parseTypealiasTarget(CommonTree target)
898 throws ParseException {
866e5b51
FC
899
900 List<CommonTree> children = target.getChildren();
866e5b51
FC
901
902 CommonTree typeSpecifierList = null;
903 CommonTree typeDeclaratorList = null;
904 CommonTree typeDeclarator = null;
905 StringBuilder identifierSB = new StringBuilder();
906
907 for (CommonTree child : children) {
908 switch (child.getType()) {
909 case CTFParser.TYPE_SPECIFIER_LIST:
866e5b51
FC
910 typeSpecifierList = child;
911 break;
912 case CTFParser.TYPE_DECLARATOR_LIST:
866e5b51
FC
913 typeDeclaratorList = child;
914 break;
915 default:
916 childTypeError(child);
917 break;
918 }
919 }
920
866e5b51
FC
921
922 if (typeDeclaratorList != null) {
923 /*
924 * Only allow one declarator
925 *
926 * eg: "typealias uint8_t *, ** := puint8_t;" is not permitted,
927 * otherwise the new type puint8_t would maps to two different
928 * types.
929 */
930 if (typeDeclaratorList.getChildCount() != 1) {
931 throw new ParseException(
932 "Only one type declarator is allowed in the typealias target"); //$NON-NLS-1$
933 }
934
935 typeDeclarator = (CommonTree) typeDeclaratorList.getChild(0);
936 }
937
938 /* Parse the target type and get the declaration */
939 IDeclaration targetDeclaration = parseTypeDeclarator(typeDeclarator,
940 typeSpecifierList, identifierSB);
941
942 /*
943 * We don't allow identifier in the target
944 *
945 * eg: "typealias uint8_t* hello := puint8_t;", the "hello" is not
946 * permitted
947 */
948 if (identifierSB.length() > 0) {
949 throw new ParseException("Identifier (" + identifierSB.toString() //$NON-NLS-1$
950 + ") not expected in the typealias target"); //$NON-NLS-1$
951 }
952
953 return targetDeclaration;
954 }
955
956 /**
957 * Parses the alias part of a typealias. It parses the underlying specifier
958 * list and declarator and creates the string representation that will be
959 * used to register the type.
960 *
961 * @param alias
962 * A TYPEALIAS_ALIAS node.
963 * @return The string representation of the alias.
964 * @throws ParseException
965 */
966 private static String parseTypealiasAlias(CommonTree alias)
967 throws ParseException {
866e5b51
FC
968
969 List<CommonTree> children = alias.getChildren();
866e5b51
FC
970
971 CommonTree typeSpecifierList = null;
972 CommonTree typeDeclaratorList = null;
973 CommonTree typeDeclarator = null;
974 List<CommonTree> pointers = new LinkedList<CommonTree>();
975
976 for (CommonTree child : children) {
977 switch (child.getType()) {
978 case CTFParser.TYPE_SPECIFIER_LIST:
866e5b51
FC
979 typeSpecifierList = child;
980 break;
981 case CTFParser.TYPE_DECLARATOR_LIST:
866e5b51
FC
982 typeDeclaratorList = child;
983 break;
984 default:
985 childTypeError(child);
986 break;
987 }
988 }
989
990 /* If there is a type declarator list, extract the pointers */
991 if (typeDeclaratorList != null) {
992 /*
993 * Only allow one declarator
994 *
995 * eg: "typealias uint8_t := puint8_t *, **;" is not permitted.
996 */
997 if (typeDeclaratorList.getChildCount() != 1) {
998 throw new ParseException(
999 "Only one type declarator is allowed in the typealias alias"); //$NON-NLS-1$
1000 }
1001
1002 typeDeclarator = (CommonTree) typeDeclaratorList.getChild(0);
1003
72dbc4ac 1004 List<CommonTree> typeDeclaratorChildren = typeDeclarator.getChildren();
866e5b51
FC
1005
1006 for (CommonTree child : typeDeclaratorChildren) {
1007 switch (child.getType()) {
1008 case CTFParser.POINTER:
1009 pointers.add(child);
1010 break;
1011 case CTFParser.IDENTIFIER:
1012 throw new ParseException("Identifier (" + child.getText() //$NON-NLS-1$
1013 + ") not expected in the typealias target"); //$NON-NLS-1$
1014 /* break; */
1015 default:
1016 childTypeError(child);
1017 break;
1018 }
1019 }
1020 }
1021
1022 return createTypeDeclarationString(typeSpecifierList, pointers);
1023 }
1024
1025 /**
1026 * Parses a typedef node. This creates and registers a new declaration for
1027 * each declarator found in the typedef.
1028 *
1029 * @param typedef
1030 * A TYPEDEF node.
1031 * @throws ParseException
1032 * If there is an error creating the declaration.
1033 */
1034 private void parseTypedef(CommonTree typedef) throws ParseException {
866e5b51 1035
72dbc4ac 1036 CommonTree typeDeclaratorListNode = (CommonTree) typedef.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
866e5b51 1037
72dbc4ac 1038 CommonTree typeSpecifierListNode = (CommonTree) typedef.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
866e5b51 1039
72dbc4ac 1040 List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren();
866e5b51
FC
1041
1042 for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
1043 StringBuilder identifierSB = new StringBuilder();
1044
1045 IDeclaration type_declaration = parseTypeDeclarator(
1046 typeDeclaratorNode, typeSpecifierListNode, identifierSB);
1047
1048 if (type_declaration instanceof VariantDeclaration) {
1049 if (((VariantDeclaration) type_declaration).isTagged()) {
1050 throw new ParseException(
1051 "Typealias of untagged variant is not permitted"); //$NON-NLS-1$
1052 }
1053 }
1054
1055 getCurrentScope().registerType(identifierSB.toString(),
1056 type_declaration);
1057 }
1058 }
1059
1060 /**
1061 * Parses a pair type declarator / type specifier list and returns the
1062 * corresponding declaration. If it is present, it also writes the
1063 * identifier of the declarator in the given {@link StringBuilder}.
1064 *
1065 * @param typeDeclarator
1066 * A TYPE_DECLARATOR node.
1067 * @param typeSpecifierList
1068 * A TYPE_SPECIFIER_LIST node.
1069 * @param identifierSB
1070 * A StringBuilder that will receive the identifier found in the
1071 * declarator.
1072 * @return The corresponding declaration.
1073 * @throws ParseException
1074 * If there is an error finding or creating the declaration.
1075 */
1076 private IDeclaration parseTypeDeclarator(CommonTree typeDeclarator,
1077 CommonTree typeSpecifierList, StringBuilder identifierSB)
1078 throws ParseException {
866e5b51
FC
1079
1080 IDeclaration declaration = null;
1081 List<CommonTree> children = null;
1082 List<CommonTree> pointers = new LinkedList<CommonTree>();
1083 List<CommonTree> lengths = new LinkedList<CommonTree>();
1084 CommonTree identifier = null;
1085
1086 /* Separate the tokens by type */
1087 if (typeDeclarator != null) {
1088 children = typeDeclarator.getChildren();
866e5b51
FC
1089 for (CommonTree child : children) {
1090
1091 switch (child.getType()) {
1092 case CTFParser.POINTER:
1093 pointers.add(child);
1094 break;
1095 case CTFParser.IDENTIFIER:
866e5b51
FC
1096 identifier = child;
1097 break;
1098 case CTFParser.LENGTH:
1099 lengths.add(child);
1100 break;
1101 default:
1102 childTypeError(child);
1103 break;
1104 }
1105 }
1106
1107 }
1108
1109 /*
1110 * Parse the type specifier list, which is the "base" type. For example,
1111 * it would be int in int a[3][len].
1112 */
1113 declaration = parseTypeSpecifierList(typeSpecifierList, pointers);
1114
1115 /*
1116 * Each length subscript means that we must create a nested array or
1117 * sequence. For example, int a[3][len] means that we have an array of 3
1118 * (sequences of length 'len' of (int)).
1119 */
32ede2ec 1120 if (lengths.size() > 0) {
866e5b51
FC
1121 /* We begin at the end */
1122 Collections.reverse(lengths);
1123
1124 for (CommonTree length : lengths) {
1125 /*
1126 * By looking at the first expression, we can determine whether
1127 * it is an array or a sequence.
1128 */
1129 List<CommonTree> lengthChildren = length.getChildren();
866e5b51
FC
1130
1131 CommonTree first = lengthChildren.get(0);
1132 if (isUnaryInteger(first)) {
1133 /* Array */
1134 int arrayLength = (int) parseUnaryInteger(first);
1135
1136 if (arrayLength < 1) {
1137 throw new ParseException("Array length is negative"); //$NON-NLS-1$
1138 }
1139
1140 /* Create the array declaration. */
1141 declaration = new ArrayDeclaration(arrayLength, declaration);
1142 } else if (isUnaryString(first)) {
1143 /* Sequence */
1144 String lengthName = concatenateUnaryStrings(lengthChildren);
1145
1146 /* Create the sequence declaration. */
1147 declaration = new SequenceDeclaration(lengthName,
1148 declaration);
1149 } else {
1150 childTypeError(first);
1151 }
1152 }
1153 }
1154
1155 if (identifier != null) {
1156 identifierSB.append(identifier.getText());
1157 }
1158
1159 return declaration;
1160 }
1161
1162 /**
1163 * Parses a type specifier list and returns the corresponding declaration.
1164 *
1165 * @param typeSpecifierList
1166 * A TYPE_SPECIFIER_LIST node.
1167 * @param pointerList
1168 * A list of POINTER nodes that apply to the specified type.
1169 * @return The corresponding declaration.
1170 * @throws ParseException
1171 * If the type has not been defined or if there is an error
1172 * creating the declaration.
1173 */
1174 private IDeclaration parseTypeSpecifierList(CommonTree typeSpecifierList,
1175 List<CommonTree> pointerList) throws ParseException {
866e5b51
FC
1176 IDeclaration declaration = null;
1177
1178 /*
1179 * By looking at the first element of the type specifier list, we can
1180 * determine which type it belongs to.
1181 */
1182 CommonTree firstChild = (CommonTree) typeSpecifierList.getChild(0);
866e5b51
FC
1183
1184 switch (firstChild.getType()) {
1185 case CTFParser.FLOATING_POINT:
53047a66 1186 declaration = parseFloat(firstChild);
866e5b51
FC
1187 break;
1188 case CTFParser.INTEGER:
1189 declaration = parseInteger(firstChild);
1190 break;
1191 case CTFParser.STRING:
1192 declaration = parseString(firstChild);
1193 break;
1194 case CTFParser.STRUCT:
1195 declaration = parseStruct(firstChild);
1196 break;
1197 case CTFParser.VARIANT:
1198 declaration = parseVariant(firstChild);
1199 break;
1200 case CTFParser.ENUM:
1201 declaration = parseEnum(firstChild);
1202 break;
1203 case CTFParser.IDENTIFIER:
1204 case CTFParser.FLOATTOK:
1205 case CTFParser.INTTOK:
1206 case CTFParser.LONGTOK:
1207 case CTFParser.SHORTTOK:
1208 case CTFParser.SIGNEDTOK:
1209 case CTFParser.UNSIGNEDTOK:
1210 case CTFParser.CHARTOK:
1211 case CTFParser.DOUBLETOK:
1212 case CTFParser.VOIDTOK:
1213 case CTFParser.BOOLTOK:
1214 case CTFParser.COMPLEXTOK:
1215 case CTFParser.IMAGINARYTOK:
1216 declaration = parseTypeDeclaration(typeSpecifierList, pointerList);
1217 break;
1218 default:
1219 childTypeError(firstChild);
1220 }
1221
866e5b51
FC
1222 return declaration;
1223 }
1224
32ede2ec
MK
1225 private IDeclaration parseFloat(CommonTree floatingPoint)
1226 throws ParseException {
53047a66
MK
1227
1228 List<CommonTree> children = floatingPoint.getChildren();
1229
1230 /*
1231 * If the integer has no attributes, then it is missing the size
1232 * attribute which is required
1233 */
1234 if (children == null) {
1235 throw new ParseException("float: missing size attribute"); //$NON-NLS-1$
1236 }
1237
1238 /* The return value */
1239 FloatDeclaration floatDeclaration = null;
1240 ByteOrder byteOrder = trace.getByteOrder();
1241 long alignment = 0;
53047a66
MK
1242 int exponent = 8;
1243 int mantissa = 24;
1244
53047a66
MK
1245 /* Iterate on all integer children */
1246 for (CommonTree child : children) {
1247 switch (child.getType()) {
1248 case CTFParser.CTF_EXPRESSION_VAL:
1249 /*
1250 * An assignment expression must have 2 children, left and right
1251 */
53047a66
MK
1252
1253 CommonTree leftNode = (CommonTree) child.getChild(0);
53047a66 1254 CommonTree rightNode = (CommonTree) child.getChild(1);
53047a66
MK
1255
1256 List<CommonTree> leftStrings = leftNode.getChildren();
53047a66
MK
1257
1258 if (!isUnaryString(leftStrings.get(0))) {
1259 throw new ParseException(
1260 "Left side of ctf expression must be a string"); //$NON-NLS-1$
1261 }
1262 String left = concatenateUnaryStrings(leftStrings);
1263
07002e0a 1264 if (left.equals(CTFStrings.EXP_DIG)) {
53047a66 1265 exponent = (int) parseUnaryInteger((CommonTree) rightNode.getChild(0));
07002e0a 1266 } else if (left.equals(CTFStrings.BYTE_ORDER)) {
53047a66 1267 byteOrder = getByteOrder(rightNode);
07002e0a 1268 } else if (left.equals(CTFStrings.MANT_DIG)) {
53047a66 1269 mantissa = (int) parseUnaryInteger((CommonTree) rightNode.getChild(0));
07002e0a 1270 } else if (left.equals(CTFStrings.ALIGN)) {
53047a66
MK
1271 alignment = getAlignment(rightNode);
1272 } else {
1273 throw new ParseException("Float: unknown attribute " + left); //$NON-NLS-1$
1274 }
1275
1276 break;
1277 default:
1278 childTypeError(child);
1279 break;
1280 }
1281 }
1282 int size = mantissa + exponent;
1283 if (size == 0) {
1284 throw new ParseException("Float missing size attribute"); //$NON-NLS-1$
1285 }
1286
1287 if (alignment == 0) {
1288 if ((size % 8) == 0) {
1289 alignment = 1;
1290 } else {
1291 alignment = 8;
1292 }
1293 }
1294
07002e0a 1295 floatDeclaration = new FloatDeclaration(exponent, mantissa, byteOrder, alignment);
53047a66 1296
53047a66
MK
1297 return floatDeclaration;
1298
1299 }
1300
866e5b51
FC
1301 /**
1302 * Parses a type specifier list as a user-declared type.
1303 *
1304 * @param typeSpecifierList
1305 * A TYPE_SPECIFIER_LIST node containing a user-declared type.
1306 * @param pointerList
1307 * A list of POINTER nodes that apply to the type specified in
1308 * typeSpecifierList.
1309 * @return The corresponding declaration.
1310 * @throws ParseException
1311 * If the type does not exist (has not been found).
1312 */
1313 private IDeclaration parseTypeDeclaration(CommonTree typeSpecifierList,
1314 List<CommonTree> pointerList) throws ParseException {
1315 /* Create the string representation of the type declaration */
1316 String typeStringRepresentation = createTypeDeclarationString(
1317 typeSpecifierList, pointerList);
1318
1319 /* Use the string representation to search the type in the current scope */
1320 IDeclaration decl = getCurrentScope().rlookupType(
1321 typeStringRepresentation);
1322
1323 if (decl == null) {
1324 throw new ParseException("Type " + typeStringRepresentation //$NON-NLS-1$
1325 + " has not been defined."); //$NON-NLS-1$
1326 }
1327
1328 return decl;
1329 }
1330
1331 /**
1332 * Parses an integer declaration node.
1333 *
1334 * @param integer
1335 * An INTEGER node.
1336 * @return The corresponding integer declaration.
1337 * @throws ParseException
1338 */
1339 private IntegerDeclaration parseInteger(CommonTree integer)
1340 throws ParseException {
866e5b51
FC
1341
1342 List<CommonTree> children = integer.getChildren();
1343
1344 /*
1345 * If the integer has no attributes, then it is missing the size
1346 * attribute which is required
1347 */
1348 if (children == null) {
1349 throw new ParseException("integer: missing size attribute"); //$NON-NLS-1$
1350 }
1351
1352 /* The return value */
1353 IntegerDeclaration integerDeclaration = null;
1354 boolean signed = false;
1355 ByteOrder byteOrder = trace.getByteOrder();
1356 long size = 0;
1357 long alignment = 0;
1358 int base = 10;
284fdee8 1359 String clock = null;
866e5b51
FC
1360
1361 Encoding encoding = Encoding.NONE;
1362
1363 /* Iterate on all integer children */
1364 for (CommonTree child : children) {
1365 switch (child.getType()) {
1366 case CTFParser.CTF_EXPRESSION_VAL:
1367 /*
1368 * An assignment expression must have 2 children, left and right
1369 */
866e5b51
FC
1370
1371 CommonTree leftNode = (CommonTree) child.getChild(0);
866e5b51 1372 CommonTree rightNode = (CommonTree) child.getChild(1);
866e5b51
FC
1373
1374 List<CommonTree> leftStrings = leftNode.getChildren();
866e5b51
FC
1375
1376 if (!isUnaryString(leftStrings.get(0))) {
1377 throw new ParseException(
1378 "Left side of ctf expression must be a string"); //$NON-NLS-1$
1379 }
1380 String left = concatenateUnaryStrings(leftStrings);
1381
1382 if (left.equals("signed")) { //$NON-NLS-1$
1383 signed = getSigned(rightNode);
07002e0a 1384 } else if (left.equals(CTFStrings.BYTE_ORDER)) {
866e5b51
FC
1385 byteOrder = getByteOrder(rightNode);
1386 } else if (left.equals("size")) { //$NON-NLS-1$
1387 size = getSize(rightNode);
07002e0a 1388 } else if (left.equals(CTFStrings.ALIGN)) {
866e5b51
FC
1389 alignment = getAlignment(rightNode);
1390 } else if (left.equals("base")) { //$NON-NLS-1$
1391 base = getBase(rightNode);
1392 } else if (left.equals("encoding")) { //$NON-NLS-1$
1393 encoding = getEncoding(rightNode);
1394 } else if (left.equals("map")) { //$NON-NLS-1$
1395 clock = getClock(rightNode);
1396 } else {
32ede2ec
MK
1397 throw new ParseException(
1398 "Integer: unknown attribute " + left); //$NON-NLS-1$
866e5b51
FC
1399 }
1400
1401 break;
1402 default:
1403 childTypeError(child);
1404 break;
1405 }
1406 }
1407
1408 if (size == 0) {
1409 throw new ParseException("Integer missing size attribute"); //$NON-NLS-1$
1410 }
1411
1412 if (alignment == 0) {
1413 if ((size % 8) == 0) {
1414 alignment = 1;
1415 } else {
1416 alignment = 8;
1417 }
1418 }
1419
1420 integerDeclaration = new IntegerDeclaration((int) size, signed, base,
fd74e6c1 1421 byteOrder, encoding, clock, alignment);
866e5b51 1422
866e5b51
FC
1423 return integerDeclaration;
1424 }
1425
284fdee8 1426 private static String getClock(CommonTree rightNode) {
866e5b51
FC
1427 return rightNode.getChild(1).getChild(0).getChild(0).getText();
1428 }
1429
1430 private static StringDeclaration parseString(CommonTree string)
1431 throws ParseException {
866e5b51
FC
1432
1433 List<CommonTree> children = string.getChildren();
1434 StringDeclaration stringDeclaration = null;
1435
1436 if (children == null) {
1437 stringDeclaration = new StringDeclaration();
1438 } else {
1439 Encoding encoding = Encoding.UTF8;
1440 for (CommonTree child : children) {
1441 switch (child.getType()) {
1442 case CTFParser.CTF_EXPRESSION_VAL:
1443 /*
1444 * An assignment expression must have 2 children, left and
1445 * right
1446 */
866e5b51
FC
1447
1448 CommonTree leftNode = (CommonTree) child.getChild(0);
866e5b51 1449 CommonTree rightNode = (CommonTree) child.getChild(1);
866e5b51
FC
1450
1451 List<CommonTree> leftStrings = leftNode.getChildren();
866e5b51
FC
1452
1453 if (!isUnaryString(leftStrings.get(0))) {
1454 throw new ParseException(
1455 "Left side of ctf expression must be a string"); //$NON-NLS-1$
1456 }
1457 String left = concatenateUnaryStrings(leftStrings);
1458
1459 if (left.equals("encoding")) { //$NON-NLS-1$
1460 encoding = getEncoding(rightNode);
1461 } else {
1462 throw new ParseException("String: unknown attribute " //$NON-NLS-1$
1463 + left);
1464 }
1465
1466 break;
1467 default:
1468 childTypeError(child);
1469 break;
1470 }
1471 }
1472
1473 stringDeclaration = new StringDeclaration(encoding);
1474 }
1475
1476 return stringDeclaration;
1477 }
1478
1479 /**
1480 * Parses a struct declaration and returns the corresponding declaration.
1481 *
1482 * @param struct
1483 * An STRUCT node.
1484 * @return The corresponding struct declaration.
1485 * @throws ParseException
1486 */
1487 private StructDeclaration parseStruct(CommonTree struct)
1488 throws ParseException {
866e5b51
FC
1489
1490 List<CommonTree> children = struct.getChildren();
866e5b51
FC
1491
1492 /* The return value */
1493 StructDeclaration structDeclaration = null;
1494
1495 /* Name */
1496 String structName = null;
1497 boolean hasName = false;
1498
1499 /* Body */
1500 CommonTree structBody = null;
1501 boolean hasBody = false;
1502
1503 /* Align */
1504 long structAlign = 0;
1505
1506 /* Loop on all children and identify what we have to work with. */
1507 for (CommonTree child : children) {
1508 switch (child.getType()) {
1509 case CTFParser.STRUCT_NAME: {
1510 hasName = true;
1511
72dbc4ac 1512 CommonTree structNameIdentifier = (CommonTree) child.getChild(0);
866e5b51 1513
866e5b51
FC
1514 structName = structNameIdentifier.getText();
1515
1516 break;
1517 }
1518 case CTFParser.STRUCT_BODY: {
1519 hasBody = true;
1520
1521 structBody = child;
1522
1523 break;
1524 }
1525 case CTFParser.ALIGN: {
72dbc4ac 1526 CommonTree structAlignExpression = (CommonTree) child.getChild(0);
866e5b51
FC
1527
1528 structAlign = getAlignment(structAlignExpression);
1529
1530 break;
1531 }
1532 default:
1533 childTypeError(child);
1534
1535 break;
1536 }
1537 }
1538
1539 /*
1540 * If a struct has just a body and no name (just like the song,
1541 * "A Struct With No Name" by America (sorry for that...)), it's a
1542 * definition of a new type, so we create the type declaration and
1543 * return it. We can't add it to the declaration scope since there is no
1544 * name, but that's what we want because it won't be possible to use it
1545 * again to declare another field.
1546 *
1547 * If it has just a name, we look it up in the declaration scope and
1548 * return the associated declaration. If it is not found in the
1549 * declaration scope, it means that a struct with that name has not been
1550 * declared, which is an error.
1551 *
1552 * If it has both, then we create the type declaration and register it
1553 * to the current scope.
1554 *
1555 * If it has none, then what are we doing here ?
1556 */
1557 if (hasBody) {
1558 /*
1559 * If struct has a name, check if already defined in the current
1560 * scope.
1561 */
1562 if (hasName && (getCurrentScope().lookupStruct(structName) != null)) {
1563 throw new ParseException("struct " + structName //$NON-NLS-1$
1564 + " already defined."); //$NON-NLS-1$
1565 }
866e5b51
FC
1566 /* Create the declaration */
1567 structDeclaration = new StructDeclaration(structAlign);
1568
1569 /* Parse the body */
1570 parseStructBody(structBody, structDeclaration);
1571
1572 /* If struct has name, add it to the current scope. */
1573 if (hasName) {
1574 getCurrentScope().registerStruct(structName, structDeclaration);
1575 }
1576 } else /* !hasBody */{
1577 if (hasName) {
1578 /* Name and !body */
1579
1580 /* Lookup the name in the current scope. */
1581 structDeclaration = getCurrentScope().rlookupStruct(structName);
1582
1583 /*
1584 * If not found, it means that a struct with such name has not
1585 * been defined
1586 */
1587 if (structDeclaration == null) {
1588 throw new ParseException("struct " + structName //$NON-NLS-1$
1589 + " is not defined"); //$NON-NLS-1$
1590 }
1591 } else {
1592 /* !Name and !body */
1593
1594 /* We can't do anything with that. */
1595 throw new ParseException("struct with no name and no body"); //$NON-NLS-1$
1596 }
1597 }
1598
866e5b51
FC
1599 return structDeclaration;
1600 }
1601
1602 /**
1603 * Parses a struct body, adding the fields to specified structure
1604 * declaration.
1605 *
1606 * @param structBody
1607 * A STRUCT_BODY node.
1608 * @param structDeclaration
1609 * The struct declaration.
1610 * @throws ParseException
1611 */
1612 private void parseStructBody(CommonTree structBody,
1613 StructDeclaration structDeclaration) throws ParseException {
866e5b51
FC
1614
1615 List<CommonTree> structDeclarations = structBody.getChildren();
1616
1617 /*
1618 * If structDeclaration is null, structBody has no children and the
1619 * struct body is empty.
1620 */
1621 if (structDeclarations != null) {
1622 pushScope();
1623
1624 for (CommonTree declarationNode : structDeclarations) {
1625 switch (declarationNode.getType()) {
1626 case CTFParser.TYPEALIAS:
1627 parseTypealias(declarationNode);
1628 break;
1629 case CTFParser.TYPEDEF:
1630 parseTypedef(declarationNode);
1631 break;
1632 case CTFParser.SV_DECLARATION:
1633 parseStructDeclaration(declarationNode, structDeclaration);
1634 break;
1635 default:
1636 childTypeError(declarationNode);
1637 break;
1638 }
1639 }
1640 popScope();
1641 }
1642 }
1643
1644 /**
1645 * Parses a declaration found in a struct.
1646 *
1647 * @param declaration
1648 * A SV_DECLARATION node.
1649 * @param struct
1650 * A struct declaration. (I know, little name clash here...)
1651 * @throws ParseException
1652 */
1653 private void parseStructDeclaration(CommonTree declaration,
1654 StructDeclaration struct) throws ParseException {
866e5b51 1655
866e5b51
FC
1656
1657 /* Get the type specifier list node */
72dbc4ac 1658 CommonTree typeSpecifierListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
866e5b51
FC
1659
1660 /* Get the type declarator list node */
72dbc4ac 1661 CommonTree typeDeclaratorListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
866e5b51
FC
1662
1663 /* Get the type declarator list */
72dbc4ac 1664 List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren();
866e5b51
FC
1665
1666 /*
1667 * For each type declarator, parse the declaration and add a field to
1668 * the struct
1669 */
1670 for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
866e5b51
FC
1671
1672 StringBuilder identifierSB = new StringBuilder();
1673
1674 IDeclaration decl = parseTypeDeclarator(typeDeclaratorNode,
1675 typeSpecifierListNode, identifierSB);
1676 String fieldName = identifierSB.toString();
866e5b51
FC
1677
1678 if (struct.hasField(fieldName)) {
1679 throw new ParseException("struct: duplicate field " //$NON-NLS-1$
1680 + fieldName);
1681 }
1682
1683 struct.addField(fieldName, decl);
1684
1685 }
1686 }
1687
1688 /**
1689 * Parses an enum declaration and returns the corresponding declaration.
1690 *
1691 * @param _enum
1692 * An ENUM node.
1693 * @return The corresponding enum declaration.
1694 * @throws ParseException
1695 */
1696 private EnumDeclaration parseEnum(CommonTree _enum) throws ParseException {
866e5b51
FC
1697
1698 List<CommonTree> children = _enum.getChildren();
866e5b51
FC
1699
1700 /* The return value */
1701 EnumDeclaration enumDeclaration = null;
1702
1703 /* Name */
1704 String enumName = null;
1705
1706 /* Body */
1707 CommonTree enumBody = null;
1708
1709 /* Container type */
1710 IntegerDeclaration containerTypeDeclaration = null;
1711
1712 /* Loop on all children and identify what we have to work with. */
1713 for (CommonTree child : children) {
1714 switch (child.getType()) {
1715 case CTFParser.ENUM_NAME: {
866e5b51
FC
1716 CommonTree enumNameIdentifier = (CommonTree) child.getChild(0);
1717
866e5b51
FC
1718 enumName = enumNameIdentifier.getText();
1719
1720 break;
1721 }
1722 case CTFParser.ENUM_BODY: {
866e5b51
FC
1723
1724 enumBody = child;
1725
1726 break;
1727 }
1728 case CTFParser.ENUM_CONTAINER_TYPE: {
866e5b51
FC
1729
1730 containerTypeDeclaration = parseEnumContainerType(child);
1731
1732 break;
1733 }
1734 default:
1735 childTypeError(child);
1736 break;
1737 }
1738 }
1739
1740 /*
1741 * If the container type has not been defined explicitly, we assume it
1742 * is "int".
1743 */
1744 if (containerTypeDeclaration == null) {
32ede2ec
MK
1745 IDeclaration enumDecl;
1746 /*
1747 * it could be because the enum was already declared.
1748 */
1749 if (enumName != null) {
1750 enumDecl = getCurrentScope().rlookupEnum(enumName);
1751 if (enumDecl != null) {
1752 return (EnumDeclaration) enumDecl;
1753 }
1754 }
1755
866e5b51
FC
1756 IDeclaration decl = getCurrentScope().rlookupType("int"); //$NON-NLS-1$
1757
1758 if (decl == null) {
1759 throw new ParseException(
1760 "enum container type implicit and type int not defined"); //$NON-NLS-1$
1761 } else if (!(decl instanceof IntegerDeclaration)) {
1762 throw new ParseException(
1763 "enum container type implicit and type int not an integer"); //$NON-NLS-1$
1764 }
1765
1766 containerTypeDeclaration = (IntegerDeclaration) decl;
1767 }
1768
1769 /*
1770 * If it has a body, it's a new declaration, otherwise it's a reference
1771 * to an existing declaration. Same logic as struct.
1772 */
1773 if (enumBody != null) {
1774 /*
1775 * If enum has a name, check if already defined in the current
1776 * scope.
1777 */
1778 if ((enumName != null)
1779 && (getCurrentScope().lookupEnum(enumName) != null)) {
1780 throw new ParseException("enum " + enumName //$NON-NLS-1$
1781 + " already defined"); //$NON-NLS-1$
1782 }
1783
1784 /* Create the declaration */
1785 enumDeclaration = new EnumDeclaration(containerTypeDeclaration);
1786
1787 /* Parse the body */
1788 parseEnumBody(enumBody, enumDeclaration);
1789
1790 /* If the enum has name, add it to the current scope. */
1791 if (enumName != null) {
1792 getCurrentScope().registerEnum(enumName, enumDeclaration);
1793 }
1794 } else {
1795 if (enumName != null) {
1796 /* Name and !body */
1797
1798 /* Lookup the name in the current scope. */
1799 enumDeclaration = getCurrentScope().rlookupEnum(enumName);
1800
1801 /*
1802 * If not found, it means that an enum with such name has not
1803 * been defined
1804 */
1805 if (enumDeclaration == null) {
1806 throw new ParseException("enum " + enumName //$NON-NLS-1$
1807 + " is not defined"); //$NON-NLS-1$
1808 }
1809 } else {
1810 /* !Name and !body */
1811 throw new ParseException("enum with no name and no body"); //$NON-NLS-1$
1812 }
1813 }
1814
1815 return enumDeclaration;
1816
1817 }
1818
1819 /**
1820 * Parses an enum body, adding the enumerators to the specified enum
1821 * declaration.
1822 *
1823 * @param enumBody
1824 * An ENUM_BODY node.
1825 * @param enumDeclaration
1826 * The enum declaration.
1827 * @throws ParseException
1828 */
1829 private void parseEnumBody(CommonTree enumBody,
1830 EnumDeclaration enumDeclaration) throws ParseException {
866e5b51
FC
1831
1832 List<CommonTree> enumerators = enumBody.getChildren();
1833 /* enum body can't be empty (unlike struct). */
866e5b51
FC
1834
1835 pushScope();
1836
1837 /*
1838 * Start at -1, so that if the first enumrator has no explicit value, it
1839 * will choose 0
1840 */
1841 long lastHigh = -1;
1842
1843 for (CommonTree enumerator : enumerators) {
1844 lastHigh = parseEnumEnumerator(enumerator, enumDeclaration,
1845 lastHigh);
1846 }
1847
1848 popScope();
1849
1850 }
1851
1852 /**
1853 * Parses an enumerator node and adds an enumerator declaration to an
1854 * enumeration declaration.
1855 *
1856 * The high value of the range of the last enumerator is needed in case the
1857 * current enumerator does not specify its value.
1858 *
1859 * @param enumerator
1860 * An ENUM_ENUMERATOR node.
1861 * @param enumDeclaration
1862 * en enumeration declaration to which will be added the
1863 * enumerator.
1864 * @param lastHigh
1865 * The high value of the range of the last enumerator
1866 * @return The high value of the value range of the current enumerator.
1867 * @throws ParseException
1868 */
1869 private static long parseEnumEnumerator(CommonTree enumerator,
1870 EnumDeclaration enumDeclaration, long lastHigh)
1871 throws ParseException {
866e5b51
FC
1872
1873 List<CommonTree> children = enumerator.getChildren();
866e5b51
FC
1874
1875 long low = 0, high = 0;
1876 boolean valueSpecified = false;
1877 String label = null;
1878
1879 for (CommonTree child : children) {
1880 if (isUnaryString(child)) {
1881 label = parseUnaryString(child);
1882 } else if (child.getType() == CTFParser.ENUM_VALUE) {
866e5b51
FC
1883
1884 valueSpecified = true;
1885
1886 low = parseUnaryInteger((CommonTree) child.getChild(0));
1887 high = low;
1888 } else if (child.getType() == CTFParser.ENUM_VALUE_RANGE) {
866e5b51
FC
1889
1890 valueSpecified = true;
1891
1892 low = parseUnaryInteger((CommonTree) child.getChild(0));
1893 high = parseUnaryInteger((CommonTree) child.getChild(1));
1894 } else {
1895 childTypeError(child);
1896 }
1897 }
1898
866e5b51
FC
1899 if (!valueSpecified) {
1900 low = lastHigh + 1;
1901 high = low;
1902 }
1903
1904 if (low > high) {
1905 throw new ParseException("enum low value greater than high value"); //$NON-NLS-1$
1906 }
1907
1908 if (!enumDeclaration.add(low, high, label)) {
1909 throw new ParseException("enum declarator values overlap."); //$NON-NLS-1$
1910 }
1911
1912 return high;
1913 }
1914
1915 /**
1916 * Parses an enum container type node and returns the corresponding integer
1917 * type.
1918 *
1919 * @param enumContainerType
1920 * An ENUM_CONTAINER_TYPE node.
1921 * @return An integer declaration corresponding to the container type.
1922 * @throws ParseException
1923 * If the type does not parse correctly or if it is not an
1924 * integer type.
1925 */
1926 private IntegerDeclaration parseEnumContainerType(
1927 CommonTree enumContainerType) throws ParseException {
866e5b51
FC
1928
1929 /* Get the child, which should be a type specifier list */
72dbc4ac 1930 CommonTree typeSpecifierList = (CommonTree) enumContainerType.getChild(0);
866e5b51
FC
1931
1932 /* Parse it and get the corresponding declaration */
1933 IDeclaration decl = parseTypeSpecifierList(typeSpecifierList, null);
1934
1935 /* If is is an integer, return it, else throw an error */
1936 if (decl instanceof IntegerDeclaration) {
1937 return (IntegerDeclaration) decl;
1938 }
1939 throw new ParseException("enum container type must be an integer"); //$NON-NLS-1$
1940 }
1941
1942 private VariantDeclaration parseVariant(CommonTree variant)
1943 throws ParseException {
866e5b51
FC
1944
1945 List<CommonTree> children = variant.getChildren();
1946 VariantDeclaration variantDeclaration = null;
1947
1948 boolean hasName = false;
1949 String variantName = null;
1950
1951 boolean hasBody = false;
1952 CommonTree variantBody = null;
1953
1954 boolean hasTag = false;
1955 String variantTag = null;
1956
1957 for (CommonTree child : children) {
1958 switch (child.getType()) {
1959 case CTFParser.VARIANT_NAME:
866e5b51
FC
1960
1961 hasName = true;
1962
72dbc4ac 1963 CommonTree variantNameIdentifier = (CommonTree) child.getChild(0);
866e5b51 1964
866e5b51
FC
1965 variantName = variantNameIdentifier.getText();
1966
1967 break;
1968 case CTFParser.VARIANT_TAG:
866e5b51
FC
1969
1970 hasTag = true;
1971
72dbc4ac 1972 CommonTree variantTagIdentifier = (CommonTree) child.getChild(0);
866e5b51 1973
866e5b51
FC
1974 variantTag = variantTagIdentifier.getText();
1975
1976 break;
1977 case CTFParser.VARIANT_BODY:
866e5b51
FC
1978
1979 hasBody = true;
1980
1981 variantBody = child;
1982
1983 break;
1984 default:
1985 childTypeError(child);
1986 break;
1987 }
1988 }
1989
1990 if (hasBody) {
1991 /*
1992 * If variant has a name, check if already defined in the current
1993 * scope.
1994 */
1995 if (hasName
1996 && (getCurrentScope().lookupVariant(variantName) != null)) {
1997 throw new ParseException("variant " + variantName //$NON-NLS-1$
1998 + " already defined."); //$NON-NLS-1$
1999 }
2000
2001 /* Create the declaration */
2002 variantDeclaration = new VariantDeclaration();
2003
2004 /* Parse the body */
2005 parseVariantBody(variantBody, variantDeclaration);
2006
2007 /* If variant has name, add it to the current scope. */
2008 if (hasName) {
2009 getCurrentScope().registerVariant(variantName,
2010 variantDeclaration);
2011 }
2012 } else /* !hasBody */{
2013 if (hasName) {
2014 /* Name and !body */
2015
2016 /* Lookup the name in the current scope. */
2017 variantDeclaration = getCurrentScope().rlookupVariant(
2018 variantName);
2019
2020 /*
2021 * If not found, it means that a struct with such name has not
2022 * been defined
2023 */
2024 if (variantDeclaration == null) {
2025 throw new ParseException("variant " + variantName //$NON-NLS-1$
2026 + " is not defined"); //$NON-NLS-1$
2027 }
2028 } else {
2029 /* !Name and !body */
2030
2031 /* We can't do anything with that. */
2032 throw new ParseException("variant with no name and no body"); //$NON-NLS-1$
2033 }
2034 }
2035
2036 if (hasTag) {
2037 variantDeclaration.setTag(variantTag);
2038 }
2039
866e5b51
FC
2040 return variantDeclaration;
2041 }
2042
2043 private void parseVariantBody(CommonTree variantBody,
2044 VariantDeclaration variantDeclaration) throws ParseException {
866e5b51
FC
2045
2046 List<CommonTree> variantDeclarations = variantBody.getChildren();
866e5b51
FC
2047
2048 pushScope();
2049
2050 for (CommonTree declarationNode : variantDeclarations) {
2051 switch (declarationNode.getType()) {
2052 case CTFParser.TYPEALIAS:
2053 parseTypealias(declarationNode);
2054 break;
2055 case CTFParser.TYPEDEF:
2056 parseTypedef(declarationNode);
2057 break;
2058 case CTFParser.SV_DECLARATION:
2059 parseVariantDeclaration(declarationNode, variantDeclaration);
2060 break;
2061 default:
2062 childTypeError(declarationNode);
2063 break;
2064 }
2065 }
2066
2067 popScope();
2068 }
2069
2070 private void parseVariantDeclaration(CommonTree declaration,
2071 VariantDeclaration variant) throws ParseException {
866e5b51 2072
866e5b51
FC
2073
2074 /* Get the type specifier list node */
72dbc4ac 2075 CommonTree typeSpecifierListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
866e5b51
FC
2076
2077 /* Get the type declarator list node */
72dbc4ac 2078 CommonTree typeDeclaratorListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
866e5b51
FC
2079
2080 /* Get the type declarator list */
72dbc4ac 2081 List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren();
866e5b51
FC
2082
2083 /*
2084 * For each type declarator, parse the declaration and add a field to
2085 * the variant
2086 */
2087 for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
866e5b51
FC
2088
2089 StringBuilder identifierSB = new StringBuilder();
2090
2091 IDeclaration decl = parseTypeDeclarator(typeDeclaratorNode,
2092 typeSpecifierListNode, identifierSB);
2093
2094 if (variant.hasField(identifierSB.toString())) {
2095 throw new ParseException("variant: duplicate field " //$NON-NLS-1$
2096 + identifierSB.toString());
2097 }
2098
2099 variant.addField(identifierSB.toString(), decl);
2100 }
2101 }
2102
2103 /**
2104 * Creates the string representation of a type declaration (type specifier
2105 * list + pointers).
2106 *
2107 * @param typeSpecifierList
2108 * A TYPE_SPECIFIER_LIST node.
2109 * @param pointers
2110 * A list of POINTER nodes.
2111 * @return The string representation.
2112 * @throws ParseException
2113 */
2114 private static String createTypeDeclarationString(
2115 CommonTree typeSpecifierList, List<CommonTree> pointers)
2116 throws ParseException {
2117 StringBuilder sb = new StringBuilder();
2118
2119 createTypeSpecifierListString(typeSpecifierList, sb);
2120 createPointerListString(pointers, sb);
2121
2122 return sb.toString();
2123 }
2124
2125 /**
2126 * Creates the string representation of a list of type specifiers.
2127 *
2128 * @param typeSpecifierList
2129 * A TYPE_SPECIFIER_LIST node.
2130 * @param sb
2131 * A StringBuilder to which will be appended the string.
2132 * @throws ParseException
2133 */
2134 private static void createTypeSpecifierListString(
2135 CommonTree typeSpecifierList, StringBuilder sb)
2136 throws ParseException {
866e5b51
FC
2137
2138 List<CommonTree> children = typeSpecifierList.getChildren();
866e5b51
FC
2139
2140 boolean firstItem = true;
2141
2142 for (CommonTree child : children) {
2143 if (!firstItem) {
2144 sb.append(' ');
2145
2146 }
2147
2148 firstItem = false;
2149
2150 /* Append the string that represents this type specifier. */
2151 createTypeSpecifierString(child, sb);
2152 }
2153 }
2154
2155 /**
2156 * Creates the string representation of a type specifier.
2157 *
2158 * @param typeSpecifier
2159 * A TYPE_SPECIFIER node.
2160 * @param sb
2161 * A StringBuilder to which will be appended the string.
2162 * @throws ParseException
2163 */
2164 private static void createTypeSpecifierString(CommonTree typeSpecifier,
2165 StringBuilder sb) throws ParseException {
2166 switch (typeSpecifier.getType()) {
2167 case CTFParser.FLOATTOK:
2168 case CTFParser.INTTOK:
2169 case CTFParser.LONGTOK:
2170 case CTFParser.SHORTTOK:
2171 case CTFParser.SIGNEDTOK:
2172 case CTFParser.UNSIGNEDTOK:
2173 case CTFParser.CHARTOK:
2174 case CTFParser.DOUBLETOK:
2175 case CTFParser.VOIDTOK:
2176 case CTFParser.BOOLTOK:
2177 case CTFParser.COMPLEXTOK:
2178 case CTFParser.IMAGINARYTOK:
2179 case CTFParser.CONSTTOK:
2180 case CTFParser.IDENTIFIER:
2181 sb.append(typeSpecifier.getText());
2182 break;
2183 case CTFParser.STRUCT: {
72dbc4ac 2184 CommonTree structName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.STRUCT_NAME);
866e5b51
FC
2185 if (structName == null) {
2186 throw new ParseException(
2187 "nameless struct found in createTypeSpecifierString"); //$NON-NLS-1$
2188 }
866e5b51 2189
72dbc4ac 2190 CommonTree structNameIdentifier = (CommonTree) structName.getChild(0);
866e5b51
FC
2191
2192 sb.append(structNameIdentifier.getText());
2193 break;
2194 }
2195 case CTFParser.VARIANT: {
72dbc4ac 2196 CommonTree variantName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.VARIANT_NAME);
866e5b51
FC
2197 if (variantName == null) {
2198 throw new ParseException(
2199 "nameless variant found in createTypeSpecifierString"); //$NON-NLS-1$
2200 }
866e5b51 2201
72dbc4ac 2202 CommonTree variantNameIdentifier = (CommonTree) variantName.getChild(0);
866e5b51
FC
2203
2204 sb.append(variantNameIdentifier.getText());
2205 break;
2206 }
2207 case CTFParser.ENUM: {
72dbc4ac 2208 CommonTree enumName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.ENUM_NAME);
866e5b51
FC
2209 if (enumName == null) {
2210 throw new ParseException(
2211 "nameless enum found in createTypeSpecifierString"); //$NON-NLS-1$
2212 }
866e5b51
FC
2213
2214 CommonTree enumNameIdentifier = (CommonTree) enumName.getChild(0);
866e5b51
FC
2215
2216 sb.append(enumNameIdentifier.getText());
2217 break;
2218 }
2219 case CTFParser.FLOATING_POINT:
2220 case CTFParser.INTEGER:
2221 case CTFParser.STRING:
2222 throw new ParseException(
2223 "CTF type found in createTypeSpecifierString"); //$NON-NLS-1$
2224 /* break; */
2225 default:
2226 childTypeError(typeSpecifier);
2227 break;
2228 }
2229 }
2230
2231 /**
2232 * Creates the string representation of a list of pointers.
2233 *
2234 * @param pointerList
2235 * A list of pointer nodes. If pointerList is null, this function
2236 * does nothing.
2237 * @param sb
2238 * A stringbuilder to which will be appended the string.
2239 */
2240 private static void createPointerListString(List<CommonTree> pointerList,
2241 StringBuilder sb) {
2242 if (pointerList == null) {
2243 return;
2244 }
2245
2246 for (CommonTree pointer : pointerList) {
866e5b51
FC
2247
2248 sb.append(" *"); //$NON-NLS-1$
2249 if (pointer.getChildCount() > 0) {
866e5b51
FC
2250
2251 sb.append(" const"); //$NON-NLS-1$
2252 }
2253 }
2254 }
2255
866e5b51
FC
2256 /**
2257 * @param node
2258 * The node to check.
2259 * @return True if the given node is an unary string.
2260 */
2261 private static boolean isUnaryString(CommonTree node) {
72dbc4ac
MK
2262 return ((node.getType() == CTFParser.UNARY_EXPRESSION_STRING) ||
2263 (node.getType() == CTFParser.UNARY_EXPRESSION_STRING_QUOTES));
866e5b51
FC
2264 }
2265
2266 /**
2267 * @param node
2268 * The node to check.
2269 * @return True if the given node is an unary integer.
2270 */
2271 private static boolean isUnaryInteger(CommonTree node) {
72dbc4ac
MK
2272 return ((node.getType() == CTFParser.UNARY_EXPRESSION_DEC) ||
2273 (node.getType() == CTFParser.UNARY_EXPRESSION_HEX) ||
2274 (node.getType() == CTFParser.UNARY_EXPRESSION_OCT));
866e5b51
FC
2275 }
2276
2277 /**
2278 * Parses a unary string node and return the string value.
2279 *
2280 * @param unaryString
2281 * The unary string node to parse (type UNARY_EXPRESSION_STRING
2282 * or UNARY_EXPRESSION_STRING_QUOTES).
2283 * @return The string value.
2284 */
2285 /*
2286 * It would be really nice to remove the quotes earlier, such as in the
2287 * parser.
2288 */
2289 private static String parseUnaryString(CommonTree unaryString) {
866e5b51 2290
866e5b51 2291 CommonTree value = (CommonTree) unaryString.getChild(0);
866e5b51
FC
2292 String strval = value.getText();
2293
2294 /* Remove quotes */
2295 if (unaryString.getType() == CTFParser.UNARY_EXPRESSION_STRING_QUOTES) {
2296 strval = strval.substring(1, strval.length() - 1);
2297 }
2298
2299 return strval;
2300 }
2301
2302 /**
2303 * Parses an unary integer (dec, hex or oct).
2304 *
2305 * @param unaryInteger
2306 * An unary integer node.
2307 * @return The integer value.
2308 */
2309 private static long parseUnaryInteger(CommonTree unaryInteger) {
866e5b51
FC
2310
2311 List<CommonTree> children = unaryInteger.getChildren();
2312 CommonTree value = children.get(0);
2313 String strval = value.getText();
2314
2315 long intval;
2316
2317 if (unaryInteger.getType() == CTFParser.UNARY_EXPRESSION_DEC) {
2318 intval = Long.parseLong(strval, 10);
2319 } else if (unaryInteger.getType() == CTFParser.UNARY_EXPRESSION_HEX) {
2320 intval = Long.parseLong(strval, 0x10);
2321 } else { /* unaryInteger.getType() == CTFParser.UNARY_EXPRESSION_OCT */
2322 intval = Long.parseLong(strval, 010); // 010 == 0x08 == 8
2323 }
2324
2325 /* The rest of children are sign */
2326 if ((children.size() % 2) == 0) {
2327 return -intval;
2328 }
2329 return intval;
2330 }
2331
2332 private static long getMajorOrMinor(CommonTree rightNode)
2333 throws ParseException {
866e5b51
FC
2334
2335 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2336
2337 if (isUnaryInteger(firstChild)) {
2338 if (rightNode.getChildCount() > 1) {
2339 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2340 }
2341
2342 long m = parseUnaryInteger(firstChild);
2343
2344 if (m < 0) {
2345 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2346 }
2347
2348 return m;
2349 }
2350 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2351 }
2352
2353 private static UUID getUUID(CommonTree rightNode) throws ParseException {
866e5b51
FC
2354
2355 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2356
2357 if (isUnaryString(firstChild)) {
2358 if (rightNode.getChildCount() > 1) {
2359 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2360 }
2361
2362 String uuidstr = parseUnaryString(firstChild);
2363
2364 try {
2365 UUID uuid = UUID.fromString(uuidstr);
2366 return uuid;
2367 } catch (IllegalArgumentException e) {
2368 throw new ParseException("Invalid format for UUID"); //$NON-NLS-1$
2369 }
2370 }
2371 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2372 }
2373
2374 /**
2375 * Gets the value of a "signed" integer attribute.
2376 *
2377 * @param rightNode
2378 * A CTF_RIGHT node.
2379 * @return The "signed" value as a boolean.
2380 * @throws ParseException
2381 */
2382 private static boolean getSigned(CommonTree rightNode)
2383 throws ParseException {
866e5b51
FC
2384
2385 boolean ret = false;
2386 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2387
2388 if (isUnaryString(firstChild)) {
2389 String strval = concatenateUnaryStrings(rightNode.getChildren());
2390
32ede2ec
MK
2391 if (strval.equals(CTFStrings.TRUE)
2392 || strval.equals(CTFStrings.TRUE2)) {
866e5b51 2393 ret = true;
32ede2ec
MK
2394 } else if (strval.equals(CTFStrings.FALSE)
2395 || strval.equals(CTFStrings.FALSE2)) {
866e5b51
FC
2396 ret = false;
2397 } else {
2398 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2399 + firstChild.getChild(0).getText());
2400 }
2401 } else if (isUnaryInteger(firstChild)) {
2402 /* Happens if the value is something like "1234.hello" */
2403 if (rightNode.getChildCount() > 1) {
2404 throw new ParseException("Invalid boolean value"); //$NON-NLS-1$
2405 }
2406
2407 long intval = parseUnaryInteger(firstChild);
2408
2409 if (intval == 1) {
2410 ret = true;
2411 } else if (intval == 0) {
2412 ret = false;
2413 } else {
2414 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2415 + firstChild.getChild(0).getText());
2416 }
2417 } else {
2418 throw new ParseException();
2419 }
2420
2421 return ret;
2422 }
2423
2424 /**
2425 * Gets the value of a "byte_order" integer attribute.
2426 *
2427 * @param rightNode
2428 * A CTF_RIGHT node.
2429 * @return The "byte_order" value.
2430 * @throws ParseException
2431 */
2432 private ByteOrder getByteOrder(CommonTree rightNode) throws ParseException {
866e5b51
FC
2433
2434 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2435
2436 if (isUnaryString(firstChild)) {
2437 String strval = concatenateUnaryStrings(rightNode.getChildren());
2438
07002e0a 2439 if (strval.equals(CTFStrings.LE)) {
866e5b51 2440 return ByteOrder.LITTLE_ENDIAN;
32ede2ec
MK
2441 } else if (strval.equals(CTFStrings.BE)
2442 || strval.equals(CTFStrings.NETWORK)) {
866e5b51 2443 return ByteOrder.BIG_ENDIAN;
07002e0a 2444 } else if (strval.equals(CTFStrings.NATIVE)) {
866e5b51
FC
2445 return trace.getByteOrder();
2446 } else {
2447 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2448 }
2449 }
2450 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2451 }
2452
2453 /**
2454 * Determines if the given value is a valid alignment value.
2455 *
2456 * @param alignment
2457 * The value to check.
2458 * @return True if it is valid.
2459 */
2460 private static boolean isValidAlignment(long alignment) {
2461 return !((alignment <= 0) || ((alignment & (alignment - 1)) != 0));
2462 }
2463
2464 /**
2465 * Gets the value of a "size" integer attribute.
2466 *
2467 * @param rightNode
2468 * A CTF_RIGHT node.
2469 * @return The "size" value.
2470 * @throws ParseException
2471 */
2472 private static long getSize(CommonTree rightNode) throws ParseException {
866e5b51
FC
2473
2474 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2475
2476 if (isUnaryInteger(firstChild)) {
2477 if (rightNode.getChildCount() > 1) {
2478 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2479 }
2480
2481 long size = parseUnaryInteger(firstChild);
2482
2483 if (size < 1) {
2484 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2485 }
2486
2487 return size;
2488 }
2489 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2490 }
2491
2492 /**
2493 * Gets the value of a "align" integer or struct attribute.
2494 *
2495 * @param node
2496 * A CTF_RIGHT node or directly an unary integer.
2497 * @return The align value.
2498 * @throws ParseException
2499 */
2500 private static long getAlignment(CommonTree node) throws ParseException {
866e5b51
FC
2501
2502 /*
2503 * If a CTF_RIGHT node was passed, call getAlignment with the first
2504 * child
2505 */
2506 if (node.getType() == CTFParser.CTF_RIGHT) {
2507 if (node.getChildCount() > 1) {
2508 throw new ParseException("Invalid alignment value"); //$NON-NLS-1$
2509 }
2510
2511 return getAlignment((CommonTree) node.getChild(0));
2512 } else if (isUnaryInteger(node)) {
2513 long alignment = parseUnaryInteger(node);
2514
2515 if (!isValidAlignment(alignment)) {
2516 throw new ParseException("Invalid value for alignment : " //$NON-NLS-1$
2517 + alignment);
2518 }
2519
2520 return alignment;
2521 }
2522 throw new ParseException("Invalid value for alignment"); //$NON-NLS-1$
2523 }
2524
2525 /**
2526 * Gets the value of a "base" integer attribute.
2527 *
2528 * @param rightNode
2529 * An CTF_RIGHT node.
2530 * @return The "base" value.
2531 * @throws ParseException
2532 */
2533 private static int getBase(CommonTree rightNode) throws ParseException {
866e5b51
FC
2534
2535 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2536
2537 if (isUnaryInteger(firstChild)) {
2538 if (rightNode.getChildCount() > 1) {
2539 throw new ParseException("invalid base value"); //$NON-NLS-1$
2540 }
2541
2542 long intval = parseUnaryInteger(firstChild);
2543 if ((intval == 2) || (intval == 8) || (intval == 10)
2544 || (intval == 16)) {
2545 return (int) intval;
2546 }
2547 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2548 } else if (isUnaryString(firstChild)) {
2549 String strval = concatenateUnaryStrings(rightNode.getChildren());
2550
32ede2ec
MK
2551 if (strval.equals(CTFStrings.DECIMAL)
2552 || strval.equals(CTFStrings.DEC)
2553 || strval.equals(CTFStrings.DEC_CTE)
2554 || strval.equals(CTFStrings.INT_MOD)
07002e0a 2555 || strval.equals(CTFStrings.UNSIGNED_CTE)) {
866e5b51 2556 return 10;
32ede2ec
MK
2557 } else if (strval.equals(CTFStrings.HEXADECIMAL)
2558 || strval.equals(CTFStrings.HEX)
2559 || strval.equals(CTFStrings.X)
2560 || strval.equals(CTFStrings.X2)
07002e0a 2561 || strval.equals(CTFStrings.POINTER)) {
866e5b51 2562 return 16;
32ede2ec
MK
2563 } else if (strval.equals(CTFStrings.OCTAL)
2564 || strval.equals(CTFStrings.OCT)
07002e0a 2565 || strval.equals(CTFStrings.OCTAL_CTE)) {
866e5b51 2566 return 8;
32ede2ec
MK
2567 } else if (strval.equals(CTFStrings.BINARY)
2568 || strval.equals(CTFStrings.BIN)) {
866e5b51
FC
2569 return 2;
2570 } else {
2571 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2572 }
2573 } else {
2574 throw new ParseException("invalid value for base"); //$NON-NLS-1$
2575 }
2576 }
2577
2578 /**
2579 * Gets the value of an "encoding" integer attribute.
2580 *
2581 * @param rightNode
2582 * A CTF_RIGHT node.
2583 * @return The "encoding" value.
2584 * @throws ParseException
2585 */
2586 private static Encoding getEncoding(CommonTree rightNode)
2587 throws ParseException {
866e5b51
FC
2588
2589 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2590
2591 if (isUnaryString(firstChild)) {
2592 String strval = concatenateUnaryStrings(rightNode.getChildren());
2593
07002e0a 2594 if (strval.equals(CTFStrings.UTF8)) {
866e5b51 2595 return Encoding.UTF8;
07002e0a 2596 } else if (strval.equals(CTFStrings.ASCII)) {
866e5b51 2597 return Encoding.ASCII;
07002e0a 2598 } else if (strval.equals(CTFStrings.NONE)) {
866e5b51
FC
2599 return Encoding.NONE;
2600 } else {
2601 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2602 }
2603 }
2604 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2605 }
2606
2607 private static long getStreamID(CommonTree rightNode) throws ParseException {
866e5b51
FC
2608
2609 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2610
2611 if (isUnaryInteger(firstChild)) {
2612 if (rightNode.getChildCount() > 1) {
2613 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2614 }
2615
2616 long intval = parseUnaryInteger(firstChild);
2617
2618 return intval;
2619 }
2620 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2621 }
2622
2623 private static String getEventName(CommonTree rightNode)
2624 throws ParseException {
866e5b51
FC
2625
2626 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2627
2628 if (isUnaryString(firstChild)) {
2629 String str = concatenateUnaryStrings(rightNode.getChildren());
2630
2631 return str;
2632 }
2633 throw new ParseException("invalid value for event name"); //$NON-NLS-1$
2634 }
2635
2636 private static long getEventID(CommonTree rightNode) throws ParseException {
866e5b51
FC
2637
2638 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2639
2640 if (isUnaryInteger(firstChild)) {
2641 if (rightNode.getChildCount() > 1) {
2642 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2643 }
2644
2645 long intval = parseUnaryInteger(firstChild);
2646
2647 return intval;
2648 }
2649 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2650 }
2651
2652 /**
2653 * Concatenates a list of unary strings separated by arrows (->) or dots.
2654 *
2655 * @param strings
2656 * A list, first element being an unary string, subsequent
2657 * elements being ARROW or DOT nodes with unary strings as child.
2658 * @return The string representation of the unary string chain.
2659 */
2660 private static String concatenateUnaryStrings(List<CommonTree> strings) {
866e5b51
FC
2661
2662 StringBuilder sb = new StringBuilder();
2663
2664 CommonTree first = strings.get(0);
2665 sb.append(parseUnaryString(first));
2666
2667 boolean isFirst = true;
2668
2669 for (CommonTree ref : strings) {
2670 if (isFirst) {
2671 isFirst = false;
2672 continue;
2673 }
2674
866e5b51
FC
2675
2676 CommonTree id = (CommonTree) ref.getChild(0);
2677
2678 if (ref.getType() == CTFParser.ARROW) {
2679 sb.append("->"); //$NON-NLS-1$
2680 } else { /* DOT */
2681 sb.append('.');
2682 }
2683
2684 sb.append(parseUnaryString(id));
2685 }
2686
2687 return sb.toString();
2688 }
2689
2690 /**
2691 * Throws a ParseException stating that the parent-child relation between
2692 * the given node and its parent is not valid. It means that the shape of
2693 * the AST is unexpected.
2694 *
2695 * @param child
2696 * The invalid child node.
2697 * @throws ParseException
2698 */
2699 private static void childTypeError(CommonTree child) throws ParseException {
2700 CommonTree parent = (CommonTree) child.getParent();
2701 String error = "Parent " + CTFParser.tokenNames[parent.getType()] //$NON-NLS-1$
2702 + " can't have a child of type " //$NON-NLS-1$
2703 + CTFParser.tokenNames[child.getType()] + "."; //$NON-NLS-1$
2704
2705 throw new ParseException(error);
2706 }
2707
2708 // ------------------------------------------------------------------------
2709 // Scope management
2710 // ------------------------------------------------------------------------
2711
2712 /**
2713 * Adds a new declaration scope on the top of the scope stack.
2714 */
2715 private void pushScope() {
2716 scope = new DeclarationScope(scope);
2717 }
2718
2719 /**
2720 * Removes the top declaration scope from the scope stack.
2721 */
2722 private void popScope() {
866e5b51
FC
2723 scope = scope.getParentScope();
2724 }
2725
2726 /**
2727 * Returns the current declaration scope.
2728 *
2729 * @return The current declaration scope.
2730 */
2731 private DeclarationScope getCurrentScope() {
866e5b51
FC
2732 return scope;
2733 }
2734
2735}
This page took 0.202547 seconds and 5 git commands to generate.