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