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