1 /*******************************************************************************
2 * Copyright (c) 2011, 2015 Ericsson, Ecole Polytechnique de Montreal and others
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
10 * Matthew Khouzam - Initial Design and Grammar
11 * Francis Giraldeau - Initial API and implementation
12 * Simon Marchi - Initial API and implementation
13 *******************************************************************************/
15 package org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
;
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
;
26 import java
.util
.Map
.Entry
;
28 import java
.util
.UUID
;
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
.CTFTrace
;
49 import org
.eclipse
.tracecompass
.ctf
.core
.trace
.ICTFStream
;
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 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.trace
.CTFStream
;
61 import com
.google
.common
.collect
.Iterables
;
66 public class IOStructGen
{
68 // ------------------------------------------------------------------------
70 // ------------------------------------------------------------------------
72 private static final @NonNull String MAP
= "map"; //$NON-NLS-1$
73 private static final @NonNull String ENCODING
= "encoding"; //$NON-NLS-1$
74 private static final @NonNull String BASE
= "base"; //$NON-NLS-1$
75 private static final @NonNull String SIZE
= "size"; //$NON-NLS-1$
76 private static final @NonNull String SIGNED
= "signed"; //$NON-NLS-1$
77 private static final @NonNull String EMPTY_STRING
= ""; //$NON-NLS-1$
78 private static final int INTEGER_BASE_16
= 16;
79 private static final int INTEGER_BASE_10
= 10;
80 private static final int INTEGER_BASE_8
= 8;
81 private static final int INTEGER_BASE_2
= 2;
82 private static final long DEFAULT_ALIGNMENT
= 1;
83 private static final int DEFAULT_FLOAT_EXPONENT
= 8;
84 private static final int DEFAULT_FLOAT_MANTISSA
= 24;
85 private static final int DEFAULT_INT_BASE
= 10;
89 private final CTFTrace fTrace
;
90 private CommonTree fTree
;
93 * The current declaration scope.
95 private final DeclarationScope fRoot
;
96 private DeclarationScope fScope
;
99 * Data helpers needed for streaming
102 private boolean fHasBeenParsed
= false;
104 // ------------------------------------------------------------------------
106 // ------------------------------------------------------------------------
112 * the tree (ANTLR generated) with the parsed TSDL data.
114 * the trace containing the places to put all the read metadata
116 public IOStructGen(CommonTree tree
, CTFTrace trace
) {
119 fRoot
= trace
.getScope();
124 * Parse the tree and populate the trace defined in the constructor.
126 * @throws ParseException
127 * If there was a problem parsing the metadata
129 public void generate() throws ParseException
{
134 * Parse a partial tree and populate the trace defined in the constructor.
135 * Does not check for a "trace" block as there is only one in the trace and
138 * @throws ParseException
139 * If there was a problem parsing the metadata
141 public void generateFragment() throws ParseException
{
142 parseIncompleteRoot(fTree
);
145 // ------------------------------------------------------------------------
147 // ------------------------------------------------------------------------
150 * Sets a new tree to parse
153 * the new tree to parse
155 public void setTree(CommonTree newTree
) {
160 * Parse the root node.
164 * @throws ParseException
166 private void parseRoot(CommonTree root
) throws ParseException
{
168 List
<CommonTree
> children
= root
.getChildren();
170 CommonTree traceNode
= null;
171 boolean hasStreams
= false;
172 List
<CommonTree
> events
= new ArrayList
<>();
174 for (CommonTree child
: children
) {
175 final int type
= child
.getType();
177 case CTFParser
.DECLARATION
:
178 parseRootDeclaration(child
);
180 case CTFParser
.TRACE
:
181 if (traceNode
!= null) {
182 throw new ParseException("Only one trace block is allowed"); //$NON-NLS-1$
185 parseTrace(traceNode
);
187 case CTFParser
.STREAM
:
191 case CTFParser
.EVENT
:
194 case CTFParser
.CLOCK
:
198 parseEnvironment(child
);
201 throw childTypeError(child
);
204 if (traceNode
== null) {
205 throw new ParseException("Missing trace block"); //$NON-NLS-1$
207 parseEvents(events
, hasStreams
);
209 fHasBeenParsed
= true;
212 private void parseEvents(List
<CommonTree
> events
, boolean hasStreams
) throws ParseException
{
213 if (!hasStreams
&& !events
.isEmpty()) {
214 /* Add an empty stream that will have a null id */
215 fTrace
.addStream(new CTFStream(fTrace
));
217 for (CommonTree event
: events
) {
222 private void parseIncompleteRoot(CommonTree root
) throws ParseException
{
223 if (!fHasBeenParsed
) {
224 throw new ParseException("You need to run generate first"); //$NON-NLS-1$
226 List
<CommonTree
> children
= root
.getChildren();
227 List
<CommonTree
> events
= new ArrayList
<>();
229 for (CommonTree child
: children
) {
230 final int type
= child
.getType();
232 case CTFParser
.DECLARATION
:
233 parseRootDeclaration(child
);
235 case CTFParser
.TRACE
:
236 throw new ParseException("Trace block defined here, please use generate and not generateFragment to parse this fragment"); //$NON-NLS-1$
237 case CTFParser
.STREAM
:
240 case CTFParser
.EVENT
:
243 case CTFParser
.CLOCK
:
247 parseEnvironment(child
);
250 throw childTypeError(child
);
253 parseEvents(events
, !Iterables
.isEmpty(fTrace
.getStreams()));
257 private void resetScope() {
261 private void parseEnvironment(CommonTree environment
) {
262 List
<CommonTree
> children
= environment
.getChildren();
263 for (CommonTree child
: children
) {
266 left
= child
.getChild(0).getChild(0).getChild(0).getText();
267 right
= child
.getChild(1).getChild(0).getChild(0).getText();
268 fTrace
.addEnvironmentVar(left
, right
);
272 private void parseClock(CommonTree clock
) throws ParseException
{
273 List
<CommonTree
> children
= clock
.getChildren();
274 CTFClock ctfClock
= new CTFClock();
275 for (CommonTree child
: children
) {
276 final String key
= child
.getChild(0).getChild(0).getChild(0).getText();
277 final CommonTree value
= (CommonTree
) child
.getChild(1).getChild(0).getChild(0);
278 final int type
= value
.getType();
279 final String text
= value
.getText();
281 case CTFParser
.INTEGER
:
282 case CTFParser
.DECIMAL_LITERAL
:
284 * Not a pretty hack, this is to make sure that there is no
285 * number overflow due to 63 bit integers. The offset should
286 * only really be an issue in the year 2262. the tracer in C/ASM
287 * can write an offset in an unsigned 64 bit long. In java, the
288 * last bit, being set to 1 will be read as a negative number,
289 * but since it is too big a positive it will throw an
290 * exception. this will happen in 2^63 ns from 1970. Therefore
291 * 293 years from 1970
295 numValue
= Long
.parseLong(text
);
296 } catch (NumberFormatException e
) {
297 throw new ParseException("Number conversion issue with " + text
, e
); //$NON-NLS-1$
299 ctfClock
.addAttribute(key
, numValue
);
302 ctfClock
.addAttribute(key
, text
);
306 String nameValue
= ctfClock
.getName();
307 fTrace
.addClock(nameValue
, ctfClock
);
310 private void parseTrace(CommonTree traceNode
) throws ParseException
{
312 List
<CommonTree
> children
= traceNode
.getChildren();
313 if (children
== null) {
314 throw new ParseException("Trace block is empty"); //$NON-NLS-1$
319 for (CommonTree child
: children
) {
320 switch (child
.getType()) {
321 case CTFParser
.TYPEALIAS
:
322 parseTypealias(child
);
324 case CTFParser
.TYPEDEF
:
327 case CTFParser
.CTF_EXPRESSION_TYPE
:
328 case CTFParser
.CTF_EXPRESSION_VAL
:
329 parseTraceDeclaration(child
);
332 throw childTypeError(child
);
337 * If trace byte order was not specified and not using packet based
340 if (fTrace
.getByteOrder() == null) {
341 throw new ParseException("Trace byte order not set"); //$NON-NLS-1$
345 private void parseTraceDeclaration(CommonTree traceDecl
)
346 throws ParseException
{
348 /* There should be a left and right */
350 CommonTree leftNode
= (CommonTree
) traceDecl
.getChild(0);
351 CommonTree rightNode
= (CommonTree
) traceDecl
.getChild(1);
353 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
355 if (!isAnyUnaryString(leftStrings
.get(0))) {
356 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
359 String left
= concatenateUnaryStrings(leftStrings
);
361 if (left
.equals(MetadataStrings
.MAJOR
)) {
362 if (fTrace
.majorIsSet()) {
363 throw new ParseException("major is already set"); //$NON-NLS-1$
366 fTrace
.setMajor(getMajorOrMinor(rightNode
));
367 } else if (left
.equals(MetadataStrings
.MINOR
)) {
368 if (fTrace
.minorIsSet()) {
369 throw new ParseException("minor is already set"); //$NON-NLS-1$
372 fTrace
.setMinor(getMajorOrMinor(rightNode
));
373 } else if (left
.equals(MetadataStrings
.UUID_STRING
)) {
374 UUID uuid
= getUUID(rightNode
);
377 * If uuid was already set by a metadata packet, compare it to see
380 if (fTrace
.uuidIsSet()) {
381 if (fTrace
.getUUID().compareTo(uuid
) != 0) {
382 throw new ParseException("UUID mismatch. Packet says " //$NON-NLS-1$
383 + fTrace
.getUUID() + " but metadata says " + uuid
); //$NON-NLS-1$
386 fTrace
.setUUID(uuid
);
389 } else if (left
.equals(MetadataStrings
.BYTE_ORDER
)) {
390 ByteOrder byteOrder
= getByteOrder(rightNode
);
393 * If byte order was already set by a metadata packet, compare it to
396 if (fTrace
.getByteOrder() != null) {
397 if (fTrace
.getByteOrder() != byteOrder
) {
398 throw new ParseException(
399 "Endianness mismatch. Magic number says " //$NON-NLS-1$
400 + fTrace
.getByteOrder()
401 + " but metadata says " + byteOrder
); //$NON-NLS-1$
404 fTrace
.setByteOrder(byteOrder
);
406 final DeclarationScope currentScope
= getCurrentScope();
407 for (String type
: currentScope
.getTypeNames()) {
408 IDeclaration d
= currentScope
.lookupType(type
);
409 if (d
instanceof IntegerDeclaration
) {
410 addByteOrder(byteOrder
, currentScope
, type
, (IntegerDeclaration
) d
);
411 } else if (d
instanceof FloatDeclaration
) {
412 addByteOrder(byteOrder
, currentScope
, type
, (FloatDeclaration
) d
);
413 } else if (d
instanceof EnumDeclaration
) {
414 addByteOrder(byteOrder
, currentScope
, type
, (EnumDeclaration
) d
);
415 } else if (d
instanceof StructDeclaration
) {
416 setAlign(currentScope
, (StructDeclaration
) d
, byteOrder
);
420 } else if (left
.equals(MetadataStrings
.PACKET_HEADER
)) {
421 if (fTrace
.packetHeaderIsSet()) {
422 throw new ParseException("packet.header already defined"); //$NON-NLS-1$
425 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
427 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
428 throw new ParseException("packet.header expects a type specifier"); //$NON-NLS-1$
431 IDeclaration packetHeaderDecl
= parseTypeSpecifierList(typeSpecifier
);
433 if (!(packetHeaderDecl
instanceof StructDeclaration
)) {
434 throw new ParseException("packet.header expects a struct"); //$NON-NLS-1$
437 fTrace
.setPacketHeader((StructDeclaration
) packetHeaderDecl
);
439 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownTraceAttributeWarning
+ " " + left
); //$NON-NLS-1$
443 private static void addByteOrder(ByteOrder byteOrder
,
444 final DeclarationScope parentScope
, String name
,
445 IntegerDeclaration decl
) throws ParseException
{
447 if (!decl
.isByteOrderSet()) {
448 IntegerDeclaration newI
;
449 newI
= IntegerDeclaration
.createDeclaration(decl
.getLength(), decl
.isSigned(),
450 decl
.getBase(), byteOrder
, decl
.getEncoding(),
451 decl
.getClock(), decl
.getAlignment());
452 parentScope
.replaceType(name
, newI
);
456 private static void addByteOrder(ByteOrder byteOrder
, DeclarationScope parentScope
, String name
, EnumDeclaration decl
) throws ParseException
{
457 final IntegerDeclaration containerType
= decl
.getContainerType();
458 if (!decl
.isByteOrderSet()) {
459 EnumDeclaration newEnum
= new EnumDeclaration(IntegerDeclaration
.createDeclaration(containerType
.getLength(), containerType
.isSigned(),
460 containerType
.getBase(), byteOrder
, containerType
.getEncoding(),
461 containerType
.getClock(), containerType
.getAlignment()));
462 for (Entry
<String
, Pair
> entry
: decl
.getEnumTable().entrySet()) {
463 newEnum
.add(entry
.getValue().getFirst(), entry
.getValue().getSecond(), entry
.getKey());
466 parentScope
.replaceType(name
, newEnum
);
470 private static void addByteOrder(ByteOrder byteOrder
, DeclarationScope parentScope
, String name
, FloatDeclaration decl
) throws ParseException
{
471 if (!decl
.isByteOrderSet()) {
472 FloatDeclaration newFloat
= new FloatDeclaration(decl
.getExponent(), decl
.getMantissa(), byteOrder
, decl
.getAlignment());
473 parentScope
.replaceType(name
, newFloat
);
477 private void setAlign(DeclarationScope parentScope
, StructDeclaration sd
,
478 ByteOrder byteOrder
) throws ParseException
{
480 for (String s
: sd
.getFieldsList()) {
481 IDeclaration d
= sd
.getField(s
);
483 if (d
instanceof StructDeclaration
) {
484 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
486 } else if (d
instanceof VariantDeclaration
) {
487 setAlign(parentScope
, (VariantDeclaration
) d
, byteOrder
);
488 } else if (d
instanceof IntegerDeclaration
) {
489 IntegerDeclaration decl
= (IntegerDeclaration
) d
;
490 if (decl
.getByteOrder() != byteOrder
) {
491 IntegerDeclaration newI
;
492 newI
= IntegerDeclaration
.createDeclaration(decl
.getLength(),
493 decl
.isSigned(), decl
.getBase(), byteOrder
,
494 decl
.getEncoding(), decl
.getClock(),
495 decl
.getAlignment());
496 sd
.getFields().put(s
, newI
);
502 private void setAlign(DeclarationScope parentScope
, VariantDeclaration vd
,
503 ByteOrder byteOrder
) throws ParseException
{
505 for (String s
: vd
.getFields().keySet()) {
506 IDeclaration d
= vd
.getFields().get(s
);
508 if (d
instanceof StructDeclaration
) {
509 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
511 } else if (d
instanceof IntegerDeclaration
) {
512 IntegerDeclaration decl
= (IntegerDeclaration
) d
;
513 IntegerDeclaration newI
;
514 newI
= IntegerDeclaration
.createDeclaration(decl
.getLength(),
515 decl
.isSigned(), decl
.getBase(), byteOrder
,
516 decl
.getEncoding(), decl
.getClock(),
517 decl
.getAlignment());
518 vd
.getFields().put(s
, newI
);
523 private void parseStream(CommonTree streamNode
) throws ParseException
{
525 CTFStream stream
= new CTFStream(fTrace
);
527 List
<CommonTree
> children
= streamNode
.getChildren();
528 if (children
== null) {
529 throw new ParseException("Empty stream block"); //$NON-NLS-1$
532 pushScope(MetadataStrings
.STREAM
);
534 for (CommonTree child
: children
) {
535 switch (child
.getType()) {
536 case CTFParser
.TYPEALIAS
:
537 parseTypealias(child
);
539 case CTFParser
.TYPEDEF
:
542 case CTFParser
.CTF_EXPRESSION_TYPE
:
543 case CTFParser
.CTF_EXPRESSION_VAL
:
544 parseStreamDeclaration(child
, stream
);
547 throw childTypeError(child
);
551 if (stream
.isIdSet() &&
552 (!fTrace
.packetHeaderIsSet() || !fTrace
.getPacketHeader().hasField(MetadataStrings
.STREAM_ID
))) {
553 throw new ParseException("Stream has an ID, but there is no stream_id field in packet header."); //$NON-NLS-1$
556 fTrace
.addStream(stream
);
561 private void parseStreamDeclaration(CommonTree streamDecl
, CTFStream stream
)
562 throws ParseException
{
564 /* There should be a left and right */
566 CommonTree leftNode
= (CommonTree
) streamDecl
.getChild(0);
567 CommonTree rightNode
= (CommonTree
) streamDecl
.getChild(1);
569 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
571 if (!isAnyUnaryString(leftStrings
.get(0))) {
572 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
575 String left
= concatenateUnaryStrings(leftStrings
);
577 if (left
.equals(MetadataStrings
.ID
)) {
578 if (stream
.isIdSet()) {
579 throw new ParseException("stream id already defined"); //$NON-NLS-1$
582 long streamID
= getStreamID(rightNode
);
584 stream
.setId(streamID
);
585 } else if (left
.equals(MetadataStrings
.EVENT_HEADER
)) {
586 if (stream
.isEventHeaderSet()) {
587 throw new ParseException("event.header already defined"); //$NON-NLS-1$
590 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
592 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
593 throw new ParseException("event.header expects a type specifier"); //$NON-NLS-1$
596 IDeclaration eventHeaderDecl
= parseTypeSpecifierList(typeSpecifier
);
597 DeclarationScope scope
= getCurrentScope();
598 DeclarationScope eventHeaderScope
= lookupStructName(typeSpecifier
, scope
);
599 if (eventHeaderScope
== null) {
600 throw new ParseException("event.header scope not found"); //$NON-NLS-1$
602 pushScope(MetadataStrings
.EVENT
);
603 getCurrentScope().addChild(eventHeaderScope
);
604 eventHeaderScope
.setName(CTFStrings
.HEADER
);
606 if (eventHeaderDecl
instanceof StructDeclaration
) {
607 stream
.setEventHeader((StructDeclaration
) eventHeaderDecl
);
608 } else if (eventHeaderDecl
instanceof IEventHeaderDeclaration
) {
609 stream
.setEventHeader((IEventHeaderDeclaration
) eventHeaderDecl
);
611 throw new ParseException("event.header expects a struct"); //$NON-NLS-1$
614 } else if (left
.equals(MetadataStrings
.EVENT_CONTEXT
)) {
615 if (stream
.isEventContextSet()) {
616 throw new ParseException("event.context already defined"); //$NON-NLS-1$
619 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
621 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
622 throw new ParseException("event.context expects a type specifier"); //$NON-NLS-1$
625 IDeclaration eventContextDecl
= parseTypeSpecifierList(typeSpecifier
);
627 if (!(eventContextDecl
instanceof StructDeclaration
)) {
628 throw new ParseException("event.context expects a struct"); //$NON-NLS-1$
631 stream
.setEventContext((StructDeclaration
) eventContextDecl
);
632 } else if (left
.equals(MetadataStrings
.PACKET_CONTEXT
)) {
633 if (stream
.isPacketContextSet()) {
634 throw new ParseException("packet.context already defined"); //$NON-NLS-1$
637 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
639 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
640 throw new ParseException("packet.context expects a type specifier"); //$NON-NLS-1$
643 IDeclaration packetContextDecl
= parseTypeSpecifierList(typeSpecifier
);
645 if (!(packetContextDecl
instanceof StructDeclaration
)) {
646 throw new ParseException("packet.context expects a struct"); //$NON-NLS-1$
649 stream
.setPacketContext((StructDeclaration
) packetContextDecl
);
651 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownStreamAttributeWarning
+ " " + left
); //$NON-NLS-1$
655 private static DeclarationScope
lookupStructName(CommonTree typeSpecifier
, DeclarationScope scope
) {
657 * This needs a struct.struct_name.name to work, luckily, that is 99.99%
658 * of traces we receive.
660 final Tree potentialStruct
= typeSpecifier
.getChild(0);
661 DeclarationScope eventHeaderScope
= null;
662 if (potentialStruct
.getType() == (CTFParser
.STRUCT
)) {
663 final Tree potentialStructName
= potentialStruct
.getChild(0);
664 if (potentialStructName
.getType() == (CTFParser
.STRUCT_NAME
)) {
665 final String name
= potentialStructName
.getChild(0).getText();
666 eventHeaderScope
= scope
.lookupChildRecursive(name
);
670 * If that fails, maybe the struct is anonymous
672 if (eventHeaderScope
== null) {
673 eventHeaderScope
= scope
.lookupChildRecursive(MetadataStrings
.STRUCT
);
676 * This can still be null
678 return eventHeaderScope
;
681 private void parseEvent(CommonTree eventNode
) throws ParseException
{
683 List
<CommonTree
> children
= eventNode
.getChildren();
684 if (children
== null) {
685 throw new ParseException("Empty event block"); //$NON-NLS-1$
688 EventDeclaration event
= new EventDeclaration();
690 pushScope(MetadataStrings
.EVENT
);
692 for (CommonTree child
: children
) {
693 switch (child
.getType()) {
694 case CTFParser
.TYPEALIAS
:
695 parseTypealias(child
);
697 case CTFParser
.TYPEDEF
:
700 case CTFParser
.CTF_EXPRESSION_TYPE
:
701 case CTFParser
.CTF_EXPRESSION_VAL
:
702 parseEventDeclaration(child
, event
);
705 throw childTypeError(child
);
709 if (!event
.nameIsSet()) {
710 throw new ParseException("Event name not set"); //$NON-NLS-1$
714 * If the event did not specify a stream, then the trace must be single
717 if (!event
.streamIsSet()) {
718 if (fTrace
.nbStreams() > 1) {
719 throw new ParseException("Event without stream_id with more than one stream"); //$NON-NLS-1$
723 * If the event did not specify a stream, the only existing stream
724 * must not have an id. Note: That behavior could be changed, it
725 * could be possible to just get the only existing stream, whatever
728 ICTFStream iStream
= fTrace
.getStream(null);
729 if (iStream
instanceof CTFStream
) {
731 CTFStream ctfStream
= (CTFStream
) iStream
;
732 event
.setStream(ctfStream
);
734 throw new ParseException("Event without stream_id, but there is no stream without id"); //$NON-NLS-1$
739 * Add the event to the stream.
741 event
.getStream().addEvent(event
);
747 private void parseEventDeclaration(CommonTree eventDecl
,
748 EventDeclaration event
) throws ParseException
{
750 /* There should be a left and right */
752 CommonTree leftNode
= (CommonTree
) eventDecl
.getChild(0);
753 CommonTree rightNode
= (CommonTree
) eventDecl
.getChild(1);
755 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
757 if (!isAnyUnaryString(leftStrings
.get(0))) {
758 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
761 String left
= concatenateUnaryStrings(leftStrings
);
763 if (left
.equals(MetadataStrings
.NAME2
)) {
764 if (event
.nameIsSet()) {
765 throw new ParseException("name already defined"); //$NON-NLS-1$
768 String name
= getEventName(rightNode
);
771 } else if (left
.equals(MetadataStrings
.ID
)) {
772 if (event
.idIsSet()) {
773 throw new ParseException("id already defined"); //$NON-NLS-1$
776 long id
= getEventID(rightNode
);
777 if (id
> Integer
.MAX_VALUE
) {
778 throw new ParseException("id is greater than int.maxvalue, unsupported. id : " + id
); //$NON-NLS-1$
781 throw new ParseException("negative id, unsupported. id : " + id
); //$NON-NLS-1$
783 event
.setId((int) id
);
784 } else if (left
.equals(MetadataStrings
.STREAM_ID
)) {
785 if (event
.streamIsSet()) {
786 throw new ParseException("stream id already defined"); //$NON-NLS-1$
789 long streamId
= getStreamID(rightNode
);
791 ICTFStream iStream
= fTrace
.getStream(streamId
);
793 if (iStream
instanceof CTFStream
) {
794 CTFStream stream
= (CTFStream
) iStream
;
795 event
.setStream(stream
);
797 throw new ParseException("Stream " + streamId
+ " not found"); //$NON-NLS-1$ //$NON-NLS-2$
800 } else if (left
.equals(MetadataStrings
.CONTEXT
)) {
801 if (event
.contextIsSet()) {
802 throw new ParseException("context already defined"); //$NON-NLS-1$
805 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
807 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
808 throw new ParseException("context expects a type specifier"); //$NON-NLS-1$
811 IDeclaration contextDecl
= parseTypeSpecifierList(typeSpecifier
);
813 if (!(contextDecl
instanceof StructDeclaration
)) {
814 throw new ParseException("context expects a struct"); //$NON-NLS-1$
817 event
.setContext((StructDeclaration
) contextDecl
);
818 } else if (left
.equals(MetadataStrings
.FIELDS_STRING
)) {
819 if (event
.fieldsIsSet()) {
820 throw new ParseException("fields already defined"); //$NON-NLS-1$
823 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
825 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
826 throw new ParseException("fields expects a type specifier"); //$NON-NLS-1$
829 IDeclaration fieldsDecl
;
830 fieldsDecl
= parseTypeSpecifierList(typeSpecifier
);
832 if (!(fieldsDecl
instanceof StructDeclaration
)) {
833 throw new ParseException("fields expects a struct"); //$NON-NLS-1$
836 * The underscores in the event names. These underscores were added
837 * by the LTTng tracer.
839 final StructDeclaration fields
= (StructDeclaration
) fieldsDecl
;
840 event
.setFields(fields
);
841 } else if (left
.equals(MetadataStrings
.LOGLEVEL2
)) {
842 long logLevel
= parseUnaryInteger((CommonTree
) rightNode
.getChild(0));
843 event
.setLogLevel(logLevel
);
845 /* Custom event attribute, we'll add it to the attributes map */
846 String right
= parseUnaryString((CommonTree
) rightNode
.getChild(0));
847 event
.setCustomAttribute(left
, right
);
852 * Parses a declaration at the root level.
855 * The declaration subtree.
856 * @throws ParseException
858 private void parseRootDeclaration(CommonTree declaration
)
859 throws ParseException
{
861 List
<CommonTree
> children
= declaration
.getChildren();
863 for (CommonTree child
: children
) {
864 switch (child
.getType()) {
865 case CTFParser
.TYPEDEF
:
868 case CTFParser
.TYPEALIAS
:
869 parseTypealias(child
);
871 case CTFParser
.TYPE_SPECIFIER_LIST
:
872 parseTypeSpecifierList(child
);
875 throw childTypeError(child
);
881 * Parses a typealias node. It parses the target, the alias, and registers
882 * the type in the current scope.
886 * @throws ParseException
888 private void parseTypealias(CommonTree typealias
) throws ParseException
{
890 List
<CommonTree
> children
= typealias
.getChildren();
892 CommonTree target
= null;
893 CommonTree alias
= null;
895 for (CommonTree child
: children
) {
896 switch (child
.getType()) {
897 case CTFParser
.TYPEALIAS_TARGET
:
900 case CTFParser
.TYPEALIAS_ALIAS
:
904 throw childTypeError(child
);
908 IDeclaration targetDeclaration
= parseTypealiasTarget(target
);
910 if ((targetDeclaration
instanceof VariantDeclaration
)
911 && ((VariantDeclaration
) targetDeclaration
).isTagged()) {
912 throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
915 String aliasString
= parseTypealiasAlias(alias
);
917 getCurrentScope().registerType(aliasString
, targetDeclaration
);
921 * Parses the target part of a typealias and gets the corresponding
925 * A TYPEALIAS_TARGET node.
926 * @return The corresponding declaration.
927 * @throws ParseException
929 private IDeclaration
parseTypealiasTarget(CommonTree target
)
930 throws ParseException
{
932 List
<CommonTree
> children
= target
.getChildren();
934 CommonTree typeSpecifierList
= null;
935 CommonTree typeDeclaratorList
= null;
936 CommonTree typeDeclarator
= null;
937 StringBuilder identifierSB
= new StringBuilder();
939 for (CommonTree child
: children
) {
940 switch (child
.getType()) {
941 case CTFParser
.TYPE_SPECIFIER_LIST
:
942 typeSpecifierList
= child
;
944 case CTFParser
.TYPE_DECLARATOR_LIST
:
945 typeDeclaratorList
= child
;
948 throw childTypeError(child
);
952 if (typeDeclaratorList
!= null) {
954 * Only allow one declarator
956 * eg: "typealias uint8_t *, ** := puint8_t;" is not permitted,
957 * otherwise the new type puint8_t would maps to two different
960 if (typeDeclaratorList
.getChildCount() != 1) {
961 throw new ParseException("Only one type declarator is allowed in the typealias target"); //$NON-NLS-1$
964 typeDeclarator
= (CommonTree
) typeDeclaratorList
.getChild(0);
967 /* Parse the target type and get the declaration */
968 IDeclaration targetDeclaration
= parseTypeDeclarator(typeDeclarator
,
969 typeSpecifierList
, identifierSB
);
972 * We don't allow identifier in the target
974 * eg: "typealias uint8_t* hello := puint8_t;", the "hello" is not
977 if (identifierSB
.length() > 0) {
978 throw new ParseException("Identifier (" + identifierSB
.toString() //$NON-NLS-1$
979 + ") not expected in the typealias target"); //$NON-NLS-1$
982 return targetDeclaration
;
986 * Parses the alias part of a typealias. It parses the underlying specifier
987 * list and declarator and creates the string representation that will be
988 * used to register the type.
991 * A TYPEALIAS_ALIAS node.
992 * @return The string representation of the alias.
993 * @throws ParseException
995 private static String
parseTypealiasAlias(CommonTree alias
)
996 throws ParseException
{
998 List
<CommonTree
> children
= alias
.getChildren();
1000 CommonTree typeSpecifierList
= null;
1001 CommonTree typeDeclaratorList
= null;
1002 CommonTree typeDeclarator
= null;
1003 List
<CommonTree
> pointers
= new LinkedList
<>();
1005 for (CommonTree child
: children
) {
1006 switch (child
.getType()) {
1007 case CTFParser
.TYPE_SPECIFIER_LIST
:
1008 typeSpecifierList
= child
;
1010 case CTFParser
.TYPE_DECLARATOR_LIST
:
1011 typeDeclaratorList
= child
;
1014 throw childTypeError(child
);
1018 /* If there is a type declarator list, extract the pointers */
1019 if (typeDeclaratorList
!= null) {
1021 * Only allow one declarator
1023 * eg: "typealias uint8_t := puint8_t *, **;" is not permitted.
1025 if (typeDeclaratorList
.getChildCount() != 1) {
1026 throw new ParseException("Only one type declarator is allowed in the typealias alias"); //$NON-NLS-1$
1029 typeDeclarator
= (CommonTree
) typeDeclaratorList
.getChild(0);
1031 List
<CommonTree
> typeDeclaratorChildren
= typeDeclarator
.getChildren();
1033 for (CommonTree child
: typeDeclaratorChildren
) {
1034 switch (child
.getType()) {
1035 case CTFParser
.POINTER
:
1036 pointers
.add(child
);
1038 case CTFParser
.IDENTIFIER
:
1039 throw new ParseException("Identifier (" + child
.getText() //$NON-NLS-1$
1040 + ") not expected in the typealias target"); //$NON-NLS-1$
1042 throw childTypeError(child
);
1047 return createTypeDeclarationString(typeSpecifierList
, pointers
);
1051 * Parses a typedef node. This creates and registers a new declaration for
1052 * each declarator found in the typedef.
1056 * @return map of type name to type declaration
1057 * @throws ParseException
1058 * If there is an error creating the declaration.
1060 private Map
<String
, IDeclaration
> parseTypedef(CommonTree typedef
) throws ParseException
{
1062 CommonTree typeDeclaratorListNode
= (CommonTree
) typedef
.getFirstChildWithType(CTFParser
.TYPE_DECLARATOR_LIST
);
1064 CommonTree typeSpecifierListNode
= (CommonTree
) typedef
.getFirstChildWithType(CTFParser
.TYPE_SPECIFIER_LIST
);
1066 List
<CommonTree
> typeDeclaratorList
= typeDeclaratorListNode
.getChildren();
1068 Map
<String
, IDeclaration
> declarations
= new HashMap
<>();
1070 for (CommonTree typeDeclaratorNode
: typeDeclaratorList
) {
1071 StringBuilder identifierSB
= new StringBuilder();
1073 IDeclaration typeDeclaration
= parseTypeDeclarator(
1074 typeDeclaratorNode
, typeSpecifierListNode
, identifierSB
);
1076 if ((typeDeclaration
instanceof VariantDeclaration
)
1077 && !((VariantDeclaration
) typeDeclaration
).isTagged()) {
1078 throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
1081 getCurrentScope().registerType(identifierSB
.toString(),
1084 declarations
.put(identifierSB
.toString(), typeDeclaration
);
1086 return declarations
;
1090 * Parses a pair type declarator / type specifier list and returns the
1091 * corresponding declaration. If it is present, it also writes the
1092 * identifier of the declarator in the given {@link StringBuilder}.
1094 * @param typeDeclarator
1095 * A TYPE_DECLARATOR node.
1096 * @param typeSpecifierList
1097 * A TYPE_SPECIFIER_LIST node.
1098 * @param identifierSB
1099 * A StringBuilder that will receive the identifier found in the
1101 * @return The corresponding declaration.
1102 * @throws ParseException
1103 * If there is an error finding or creating the declaration.
1105 private IDeclaration
parseTypeDeclarator(CommonTree typeDeclarator
,
1106 CommonTree typeSpecifierList
, StringBuilder identifierSB
)
1107 throws ParseException
{
1109 IDeclaration declaration
= null;
1110 List
<CommonTree
> children
= null;
1111 List
<CommonTree
> pointers
= new LinkedList
<>();
1112 List
<CommonTree
> lengths
= new LinkedList
<>();
1113 CommonTree identifier
= null;
1115 /* Separate the tokens by type */
1116 if (typeDeclarator
!= null) {
1117 children
= typeDeclarator
.getChildren();
1118 for (CommonTree child
: children
) {
1120 switch (child
.getType()) {
1121 case CTFParser
.POINTER
:
1122 pointers
.add(child
);
1124 case CTFParser
.IDENTIFIER
:
1127 case CTFParser
.LENGTH
:
1131 throw childTypeError(child
);
1138 * Parse the type specifier list, which is the "base" type. For example,
1139 * it would be int in int a[3][len].
1141 declaration
= parseTypeSpecifierList(typeSpecifierList
, pointers
, identifier
);
1144 * Each length subscript means that we must create a nested array or
1145 * sequence. For example, int a[3][len] means that we have an array of 3
1146 * (sequences of length 'len' of (int)).
1148 if (!lengths
.isEmpty()) {
1149 /* We begin at the end */
1150 Collections
.reverse(lengths
);
1152 for (CommonTree length
: lengths
) {
1154 * By looking at the first expression, we can determine whether
1155 * it is an array or a sequence.
1157 List
<CommonTree
> lengthChildren
= length
.getChildren();
1159 CommonTree first
= lengthChildren
.get(0);
1160 if (isUnaryInteger(first
)) {
1162 int arrayLength
= (int) parseUnaryInteger(first
);
1164 if (arrayLength
< 1) {
1165 throw new ParseException("Array length is negative"); //$NON-NLS-1$
1168 /* Create the array declaration. */
1169 declaration
= new ArrayDeclaration(arrayLength
, declaration
);
1170 } else if (isAnyUnaryString(first
)) {
1172 String lengthName
= concatenateUnaryStrings(lengthChildren
);
1174 /* check that lengthName was declared */
1175 if (isSignedIntegerField(lengthName
)) {
1176 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
1178 /* Create the sequence declaration. */
1179 declaration
= new SequenceDeclaration(lengthName
,
1181 } else if (isTrace(first
)) {
1183 String lengthName
= parseTraceScope(lengthChildren
);
1185 /* check that lengthName was declared */
1186 if (isSignedIntegerField(lengthName
)) {
1187 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
1189 /* Create the sequence declaration. */
1190 declaration
= new SequenceDeclaration(lengthName
,
1193 } else if (isStream(first
)) {
1195 String lengthName
= parseStreamScope(lengthChildren
);
1197 /* check that lengthName was declared */
1198 if (isSignedIntegerField(lengthName
)) {
1199 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
1201 /* Create the sequence declaration. */
1202 declaration
= new SequenceDeclaration(lengthName
,
1204 } else if (isEvent(first
)) {
1206 String lengthName
= parseEventScope(lengthChildren
);
1208 /* check that lengthName was declared */
1209 if (isSignedIntegerField(lengthName
)) {
1210 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
1212 /* Create the sequence declaration. */
1213 declaration
= new SequenceDeclaration(lengthName
,
1216 throw childTypeError(first
);
1221 if (identifier
!= null) {
1222 final String text
= identifier
.getText();
1223 identifierSB
.append(text
);
1224 registerType(declaration
, text
);
1230 private void registerType(IDeclaration declaration
, String identifier
) throws ParseException
{
1231 final DeclarationScope currentScope
= getCurrentScope();
1232 if (declaration
instanceof EnumDeclaration
) {
1233 if (currentScope
.lookupEnum(identifier
) == null) {
1234 currentScope
.registerEnum(identifier
, (EnumDeclaration
) declaration
);
1236 } else if (declaration
instanceof VariantDeclaration
) {
1237 currentScope
.registerVariant(identifier
, (VariantDeclaration
) declaration
);
1241 private static String
parseStreamScope(List
<CommonTree
> lengthChildren
) throws ParseException
{
1242 List
<CommonTree
> sublist
= lengthChildren
.subList(1, lengthChildren
.size());
1244 CommonTree nextElem
= (CommonTree
) lengthChildren
.get(1).getChild(0);
1245 String lengthName
= null;
1246 if (isUnaryString(nextElem
)) {
1247 lengthName
= parseUnaryString(nextElem
);
1250 int type
= nextElem
.getType();
1251 if ((CTFParser
.tokenNames
[CTFParser
.EVENT
]).equals(lengthName
)) {
1252 type
= CTFParser
.EVENT
;
1255 case CTFParser
.IDENTIFIER
:
1256 lengthName
= concatenateUnaryStrings(sublist
);
1258 case CTFParser
.EVENT
:
1259 lengthName
= parseEventScope(sublist
);
1262 if (lengthName
== null) {
1263 throw new ParseException("Unsupported scope stream." + nextElem
); //$NON-NLS-1$
1266 return MetadataStrings
.STREAM
+ '.' + lengthName
;
1269 private static String
parseEventScope(List
<CommonTree
> lengthChildren
) throws ParseException
{
1270 CommonTree nextElem
= (CommonTree
) lengthChildren
.get(1).getChild(0);
1272 switch (nextElem
.getType()) {
1273 case CTFParser
.UNARY_EXPRESSION_STRING
:
1274 case CTFParser
.IDENTIFIER
:
1275 List
<CommonTree
> sublist
= lengthChildren
.subList(1, lengthChildren
.size());
1276 lengthName
= MetadataStrings
.EVENT
+ '.' + concatenateUnaryStrings(sublist
);
1279 throw new ParseException("Unsupported scope event." + nextElem
); //$NON-NLS-1$
1284 private static String
parseTraceScope(List
<CommonTree
> lengthChildren
) throws ParseException
{
1285 CommonTree nextElem
= (CommonTree
) lengthChildren
.get(1).getChild(0);
1287 switch (nextElem
.getType()) {
1288 case CTFParser
.IDENTIFIER
:
1289 lengthName
= concatenateUnaryStrings(lengthChildren
.subList(1, lengthChildren
.size()));
1291 case CTFParser
.STREAM
:
1292 return parseStreamScope(lengthChildren
.subList(1, lengthChildren
.size()));
1294 throw new ParseException("Unsupported scope trace." + nextElem
); //$NON-NLS-1$
1299 private static boolean isEvent(CommonTree first
) {
1300 return first
.getType() == CTFParser
.EVENT
;
1303 private static boolean isStream(CommonTree first
) {
1304 return first
.getType() == CTFParser
.STREAM
;
1307 private static boolean isTrace(CommonTree first
) {
1308 return first
.getType() == CTFParser
.TRACE
;
1311 private boolean isSignedIntegerField(String lengthName
) throws ParseException
{
1312 IDeclaration decl
= getCurrentScope().lookupIdentifierRecursive(lengthName
);
1313 if (decl
instanceof IntegerDeclaration
) {
1314 return ((IntegerDeclaration
) decl
).isSigned();
1316 throw new ParseException("Is not an integer: " + lengthName
); //$NON-NLS-1$
1320 private IDeclaration
parseTypeSpecifierList(CommonTree typeSpecifierList
) throws ParseException
{
1321 return parseTypeSpecifierList(typeSpecifierList
, null, null);
1325 * Parses a type specifier list and returns the corresponding declaration.
1327 * @param typeSpecifierList
1328 * A TYPE_SPECIFIER_LIST node.
1329 * @param pointerList
1330 * A list of POINTER nodes that apply to the specified type.
1331 * @return The corresponding declaration.
1332 * @throws ParseException
1333 * If the type has not been defined or if there is an error
1334 * creating the declaration.
1336 private IDeclaration
parseTypeSpecifierList(CommonTree typeSpecifierList
,
1337 List
<CommonTree
> pointerList
, CommonTree identifier
) throws ParseException
{
1338 IDeclaration declaration
= null;
1341 * By looking at the first element of the type specifier list, we can
1342 * determine which type it belongs to.
1344 CommonTree firstChild
= (CommonTree
) typeSpecifierList
.getChild(0);
1346 switch (firstChild
.getType()) {
1347 case CTFParser
.FLOATING_POINT
:
1348 declaration
= parseFloat(firstChild
);
1350 case CTFParser
.INTEGER
:
1351 declaration
= parseInteger(firstChild
);
1353 case CTFParser
.STRING
:
1354 declaration
= parseString(firstChild
);
1356 case CTFParser
.STRUCT
:
1357 declaration
= parseStruct(firstChild
, identifier
);
1358 StructDeclaration structDeclaration
= (StructDeclaration
) declaration
;
1359 IDeclaration idEnumDecl
= structDeclaration
.getFields().get("id"); //$NON-NLS-1$
1360 if (idEnumDecl
instanceof EnumDeclaration
) {
1361 EnumDeclaration enumDeclaration
= (EnumDeclaration
) idEnumDecl
;
1362 ByteOrder bo
= enumDeclaration
.getContainerType().getByteOrder();
1363 if (EventHeaderCompactDeclaration
.getEventHeader(bo
).isCompactEventHeader(structDeclaration
)) {
1364 declaration
= EventHeaderCompactDeclaration
.getEventHeader(bo
);
1365 } else if (EventHeaderLargeDeclaration
.getEventHeader(bo
).isLargeEventHeader(structDeclaration
)) {
1366 declaration
= EventHeaderLargeDeclaration
.getEventHeader(bo
);
1370 case CTFParser
.VARIANT
:
1371 declaration
= parseVariant(firstChild
);
1373 case CTFParser
.ENUM
:
1374 declaration
= parseEnum(firstChild
);
1376 case CTFParser
.IDENTIFIER
:
1377 case CTFParser
.FLOATTOK
:
1378 case CTFParser
.INTTOK
:
1379 case CTFParser
.LONGTOK
:
1380 case CTFParser
.SHORTTOK
:
1381 case CTFParser
.SIGNEDTOK
:
1382 case CTFParser
.UNSIGNEDTOK
:
1383 case CTFParser
.CHARTOK
:
1384 case CTFParser
.DOUBLETOK
:
1385 case CTFParser
.VOIDTOK
:
1386 case CTFParser
.BOOLTOK
:
1387 case CTFParser
.COMPLEXTOK
:
1388 case CTFParser
.IMAGINARYTOK
:
1389 declaration
= parseTypeDeclaration(typeSpecifierList
, pointerList
);
1392 throw childTypeError(firstChild
);
1398 private IDeclaration
parseFloat(CommonTree floatingPoint
)
1399 throws ParseException
{
1401 List
<CommonTree
> children
= floatingPoint
.getChildren();
1404 * If the integer has no attributes, then it is missing the size
1405 * attribute which is required
1407 if (children
== null) {
1408 throw new ParseException("float: missing size attribute"); //$NON-NLS-1$
1411 /* The return value */
1412 FloatDeclaration floatDeclaration
= null;
1413 ByteOrder byteOrder
= fTrace
.getByteOrder();
1416 int exponent
= DEFAULT_FLOAT_EXPONENT
;
1417 int mantissa
= DEFAULT_FLOAT_MANTISSA
;
1419 /* Iterate on all integer children */
1420 for (CommonTree child
: children
) {
1421 switch (child
.getType()) {
1422 case CTFParser
.CTF_EXPRESSION_VAL
:
1424 * An assignment expression must have 2 children, left and right
1427 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1428 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1430 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1432 if (!isAnyUnaryString(leftStrings
.get(0))) {
1433 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1435 String left
= concatenateUnaryStrings(leftStrings
);
1437 if (left
.equals(MetadataStrings
.EXP_DIG
)) {
1438 exponent
= (int) parseUnaryInteger((CommonTree
) rightNode
.getChild(0));
1439 } else if (left
.equals(MetadataStrings
.BYTE_ORDER
)) {
1440 byteOrder
= getByteOrder(rightNode
);
1441 } else if (left
.equals(MetadataStrings
.MANT_DIG
)) {
1442 mantissa
= (int) parseUnaryInteger((CommonTree
) rightNode
.getChild(0));
1443 } else if (left
.equals(MetadataStrings
.ALIGN
)) {
1444 alignment
= getAlignment(rightNode
);
1446 throw new ParseException("Float: unknown attribute " + left
); //$NON-NLS-1$
1451 throw childTypeError(child
);
1454 int size
= mantissa
+ exponent
;
1456 throw new ParseException("Float missing size attribute"); //$NON-NLS-1$
1459 if (alignment
== 0) {
1460 alignment
= DEFAULT_ALIGNMENT
;
1463 floatDeclaration
= new FloatDeclaration(exponent
, mantissa
, byteOrder
, alignment
);
1465 return floatDeclaration
;
1470 * Parses a type specifier list as a user-declared type.
1472 * @param typeSpecifierList
1473 * A TYPE_SPECIFIER_LIST node containing a user-declared type.
1474 * @param pointerList
1475 * A list of POINTER nodes that apply to the type specified in
1476 * typeSpecifierList.
1477 * @return The corresponding declaration.
1478 * @throws ParseException
1479 * If the type does not exist (has not been found).
1481 private IDeclaration
parseTypeDeclaration(CommonTree typeSpecifierList
,
1482 List
<CommonTree
> pointerList
) throws ParseException
{
1483 /* Create the string representation of the type declaration */
1484 String typeStringRepresentation
= createTypeDeclarationString(
1485 typeSpecifierList
, pointerList
);
1488 * Use the string representation to search the type in the current scope
1490 IDeclaration decl
= getCurrentScope().lookupTypeRecursive(
1491 typeStringRepresentation
);
1494 throw new ParseException("Type " + typeStringRepresentation
//$NON-NLS-1$
1495 + " has not been defined."); //$NON-NLS-1$
1502 * Parses an integer declaration node.
1506 * @return The corresponding integer declaration.
1507 * @throws ParseException
1509 private IntegerDeclaration
parseInteger(CommonTree integer
)
1510 throws ParseException
{
1512 List
<CommonTree
> children
= integer
.getChildren();
1515 * If the integer has no attributes, then it is missing the size
1516 * attribute which is required
1518 if (children
== null) {
1519 throw new ParseException("integer: missing size attribute"); //$NON-NLS-1$
1522 /* The return value */
1523 IntegerDeclaration integerDeclaration
= null;
1524 boolean signed
= false;
1525 ByteOrder byteOrder
= fTrace
.getByteOrder();
1528 int base
= DEFAULT_INT_BASE
;
1530 String clock
= EMPTY_STRING
;
1532 Encoding encoding
= Encoding
.NONE
;
1534 /* Iterate on all integer children */
1535 for (CommonTree child
: children
) {
1536 switch (child
.getType()) {
1537 case CTFParser
.CTF_EXPRESSION_VAL
:
1539 * An assignment expression must have 2 children, left and right
1542 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1543 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1545 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1547 if (!isAnyUnaryString(leftStrings
.get(0))) {
1548 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1550 String left
= concatenateUnaryStrings(leftStrings
);
1552 if (left
.equals(SIGNED
)) {
1553 signed
= getSigned(rightNode
);
1554 } else if (left
.equals(MetadataStrings
.BYTE_ORDER
)) {
1555 byteOrder
= getByteOrder(rightNode
);
1556 } else if (left
.equals(SIZE
)) {
1557 size
= getSize(rightNode
);
1558 } else if (left
.equals(MetadataStrings
.ALIGN
)) {
1559 alignment
= getAlignment(rightNode
);
1560 } else if (left
.equals(BASE
)) {
1561 base
= getBase(rightNode
);
1562 } else if (left
.equals(ENCODING
)) {
1563 encoding
= getEncoding(rightNode
);
1564 } else if (left
.equals(MAP
)) {
1565 clock
= getClock(rightNode
);
1567 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownIntegerAttributeWarning
+ " " + left
); //$NON-NLS-1$
1572 throw childTypeError(child
);
1577 throw new ParseException("Invalid size attribute in Integer: " + size
); //$NON-NLS-1$
1580 if (alignment
== 0) {
1581 alignment
= DEFAULT_ALIGNMENT
;
1584 integerDeclaration
= IntegerDeclaration
.createDeclaration((int) size
, signed
, base
,
1585 byteOrder
, encoding
, clock
, alignment
);
1587 return integerDeclaration
;
1591 private static String
getClock(CommonTree rightNode
) {
1592 String clock
= rightNode
.getChild(1).getChild(0).getChild(0).getText();
1593 return clock
== null ? EMPTY_STRING
: clock
;
1596 private static StringDeclaration
parseString(CommonTree string
)
1597 throws ParseException
{
1599 List
<CommonTree
> children
= string
.getChildren();
1600 StringDeclaration stringDeclaration
= null;
1602 if (children
== null) {
1603 stringDeclaration
= StringDeclaration
.getStringDeclaration(Encoding
.UTF8
);
1605 Encoding encoding
= Encoding
.UTF8
;
1606 for (CommonTree child
: children
) {
1607 switch (child
.getType()) {
1608 case CTFParser
.CTF_EXPRESSION_VAL
:
1610 * An assignment expression must have 2 children, left and
1614 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1615 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1617 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1619 if (!isAnyUnaryString(leftStrings
.get(0))) {
1620 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1622 String left
= concatenateUnaryStrings(leftStrings
);
1624 if (left
.equals(ENCODING
)) {
1625 encoding
= getEncoding(rightNode
);
1627 throw new ParseException("String: unknown attribute " //$NON-NLS-1$
1633 throw childTypeError(child
);
1637 stringDeclaration
= StringDeclaration
.getStringDeclaration(encoding
);
1640 return stringDeclaration
;
1644 * Parses a struct declaration and returns the corresponding declaration.
1648 * @return The corresponding struct declaration.
1649 * @throws ParseException
1651 private StructDeclaration
parseStruct(CommonTree struct
, CommonTree identifier
)
1652 throws ParseException
{
1654 List
<CommonTree
> children
= struct
.getChildren();
1656 /* The return value */
1657 StructDeclaration structDeclaration
= null;
1660 String structName
= null;
1661 boolean hasName
= false;
1664 CommonTree structBody
= null;
1665 boolean hasBody
= false;
1668 long structAlign
= 0;
1670 /* Loop on all children and identify what we have to work with. */
1671 for (CommonTree child
: children
) {
1672 switch (child
.getType()) {
1673 case CTFParser
.STRUCT_NAME
: {
1675 CommonTree structNameIdentifier
= (CommonTree
) child
.getChild(0);
1676 structName
= structNameIdentifier
.getText();
1679 case CTFParser
.STRUCT_BODY
: {
1685 case CTFParser
.ALIGN
: {
1686 CommonTree structAlignExpression
= (CommonTree
) child
.getChild(0);
1688 structAlign
= getAlignment(structAlignExpression
);
1692 throw childTypeError(child
);
1696 if (!hasName
&& identifier
!= null) {
1697 structName
= identifier
.getText();
1702 * If a struct has just a body and no name (just like the song,
1703 * "A Struct With No Name" by America (sorry for that...)), it's a
1704 * definition of a new type, so we create the type declaration and
1705 * return it. We can't add it to the declaration scope since there is no
1706 * name, but that's what we want because it won't be possible to use it
1707 * again to declare another field.
1709 * If it has just a name, we look it up in the declaration scope and
1710 * return the associated declaration. If it is not found in the
1711 * declaration scope, it means that a struct with that name has not been
1712 * declared, which is an error.
1714 * If it has both, then we create the type declaration and register it
1715 * to the current scope.
1717 * If it has none, then what are we doing here ?
1721 * If struct has a name, check if already defined in the current
1724 if (hasName
&& (getCurrentScope().lookupStruct(structName
) != null)) {
1725 throw new ParseException("struct " + structName
//$NON-NLS-1$
1726 + " already defined."); //$NON-NLS-1$
1728 /* Create the declaration */
1729 structDeclaration
= new StructDeclaration(structAlign
);
1731 /* Parse the body */
1732 parseStructBody(structBody
, structDeclaration
, structName
);
1734 /* If struct has name, add it to the current scope. */
1736 getCurrentScope().registerStruct(structName
, structDeclaration
);
1738 } else /* !hasBody */ {
1740 /* Name and !body */
1742 /* Lookup the name in the current scope. */
1743 structDeclaration
= getCurrentScope().lookupStructRecursive(structName
);
1746 * If not found, it means that a struct with such name has not
1749 if (structDeclaration
== null) {
1750 throw new ParseException("struct " + structName
//$NON-NLS-1$
1751 + " is not defined"); //$NON-NLS-1$
1754 /* !Name and !body */
1756 /* We can't do anything with that. */
1757 throw new ParseException("struct with no name and no body"); //$NON-NLS-1$
1760 return StructDeclarationFlattener
.tryFlattenStruct(structDeclaration
);
1764 * Parses a struct body, adding the fields to specified structure
1768 * A STRUCT_BODY node.
1769 * @param structDeclaration
1770 * The struct declaration.
1771 * @throws ParseException
1773 private void parseStructBody(CommonTree structBody
,
1774 StructDeclaration structDeclaration
, @Nullable String structName
) throws ParseException
{
1775 List
<CommonTree
> structDeclarations
= structBody
.getChildren();
1776 if (structDeclarations
== null) {
1777 structDeclarations
= Collections
.emptyList();
1781 * If structDeclaration is null, structBody has no children and the
1782 * struct body is empty.
1784 pushNamedScope(structName
, MetadataStrings
.STRUCT
);
1786 for (CommonTree declarationNode
: structDeclarations
) {
1787 switch (declarationNode
.getType()) {
1788 case CTFParser
.TYPEALIAS
:
1789 parseTypealias(declarationNode
);
1791 case CTFParser
.TYPEDEF
:
1792 parseTypedef(declarationNode
);
1793 parseStructDeclaration(declarationNode
, structDeclaration
);
1795 case CTFParser
.SV_DECLARATION
:
1796 parseStructDeclaration(declarationNode
, structDeclaration
);
1799 throw childTypeError(declarationNode
);
1806 * Parses a declaration found in a struct.
1808 * @param declaration
1809 * A SV_DECLARATION node.
1811 * A struct declaration. (I know, little name clash here...)
1812 * @throws ParseException
1814 private void parseStructDeclaration(CommonTree declaration
,
1815 StructDeclaration struct
) throws ParseException
{
1817 /* Get the type specifier list node */
1818 CommonTree typeSpecifierListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_SPECIFIER_LIST
);
1820 /* Get the type declarator list node */
1821 CommonTree typeDeclaratorListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_DECLARATOR_LIST
);
1823 /* Get the type declarator list */
1824 List
<CommonTree
> typeDeclaratorList
= typeDeclaratorListNode
.getChildren();
1827 * For each type declarator, parse the declaration and add a field to
1830 for (CommonTree typeDeclaratorNode
: typeDeclaratorList
) {
1832 StringBuilder identifierSB
= new StringBuilder();
1834 IDeclaration decl
= parseTypeDeclarator(typeDeclaratorNode
,
1835 typeSpecifierListNode
, identifierSB
);
1836 String fieldName
= identifierSB
.toString();
1837 getCurrentScope().registerIdentifier(fieldName
, decl
);
1839 if (struct
.hasField(fieldName
)) {
1840 throw new ParseException("struct: duplicate field " //$NON-NLS-1$
1844 struct
.addField(fieldName
, decl
);
1850 * Parses an enum declaration and returns the corresponding declaration.
1854 * @return The corresponding enum declaration.
1855 * @throws ParseException
1857 private EnumDeclaration
parseEnum(CommonTree theEnum
) throws ParseException
{
1859 List
<CommonTree
> children
= theEnum
.getChildren();
1861 /* The return value */
1862 EnumDeclaration enumDeclaration
= null;
1865 String enumName
= null;
1868 CommonTree enumBody
= null;
1870 /* Container type */
1871 IntegerDeclaration containerTypeDeclaration
= null;
1873 /* Loop on all children and identify what we have to work with. */
1874 for (CommonTree child
: children
) {
1875 switch (child
.getType()) {
1876 case CTFParser
.ENUM_NAME
: {
1877 CommonTree enumNameIdentifier
= (CommonTree
) child
.getChild(0);
1878 enumName
= enumNameIdentifier
.getText();
1881 case CTFParser
.ENUM_BODY
: {
1885 case CTFParser
.ENUM_CONTAINER_TYPE
: {
1886 containerTypeDeclaration
= parseEnumContainerType(child
);
1890 throw childTypeError(child
);
1895 * If the container type has not been defined explicitly, we assume it
1898 if (containerTypeDeclaration
== null) {
1899 IDeclaration enumDecl
;
1901 * it could be because the enum was already declared.
1903 if (enumName
!= null) {
1904 getCurrentScope().setName(enumName
);
1905 enumDecl
= getCurrentScope().lookupEnumRecursive(enumName
);
1906 if (enumDecl
!= null) {
1907 return (EnumDeclaration
) enumDecl
;
1911 IDeclaration decl
= getCurrentScope().lookupTypeRecursive("int"); //$NON-NLS-1$
1914 throw new ParseException("enum container type implicit and type int not defined"); //$NON-NLS-1$
1915 } else if (!(decl
instanceof IntegerDeclaration
)) {
1916 throw new ParseException("enum container type implicit and type int not an integer"); //$NON-NLS-1$
1919 containerTypeDeclaration
= (IntegerDeclaration
) decl
;
1923 * If it has a body, it's a new declaration, otherwise it's a reference
1924 * to an existing declaration. Same logic as struct.
1926 if (enumBody
!= null) {
1928 * If enum has a name, check if already defined in the current
1931 if ((enumName
!= null)
1932 && (getCurrentScope().lookupEnum(enumName
) != null)) {
1933 throw new ParseException("enum " + enumName
//$NON-NLS-1$
1934 + " already defined"); //$NON-NLS-1$
1937 /* Create the declaration */
1938 enumDeclaration
= new EnumDeclaration(containerTypeDeclaration
);
1940 /* Parse the body */
1941 parseEnumBody(enumBody
, enumDeclaration
, enumName
);
1943 /* If the enum has name, add it to the current scope. */
1944 if (enumName
!= null) {
1945 getCurrentScope().registerEnum(enumName
, enumDeclaration
);
1948 if (enumName
!= null) {
1949 /* Name and !body */
1951 /* Lookup the name in the current scope. */
1952 enumDeclaration
= getCurrentScope().lookupEnumRecursive(enumName
);
1955 * If not found, it means that an enum with such name has not
1958 if (enumDeclaration
== null) {
1959 throw new ParseException("enum " + enumName
//$NON-NLS-1$
1960 + " is not defined"); //$NON-NLS-1$
1963 /* !Name and !body */
1964 throw new ParseException("enum with no name and no body"); //$NON-NLS-1$
1968 return enumDeclaration
;
1973 * Parses an enum body, adding the enumerators to the specified enum
1977 * An ENUM_BODY node.
1978 * @param enumDeclaration
1979 * The enum declaration.
1980 * @throws ParseException
1982 private void parseEnumBody(CommonTree enumBody
,
1983 EnumDeclaration enumDeclaration
, @Nullable String enumName
) throws ParseException
{
1985 List
<CommonTree
> enumerators
= enumBody
.getChildren();
1986 /* enum body can't be empty (unlike struct). */
1988 pushNamedScope(enumName
, MetadataStrings
.ENUM
);
1991 * Start at -1, so that if the first enumrator has no explicit value, it
1996 for (CommonTree enumerator
: enumerators
) {
1997 lastHigh
= parseEnumEnumerator(enumerator
, enumDeclaration
,
2006 * Parses an enumerator node and adds an enumerator declaration to an
2007 * enumeration declaration.
2009 * The high value of the range of the last enumerator is needed in case the
2010 * current enumerator does not specify its value.
2013 * An ENUM_ENUMERATOR node.
2014 * @param enumDeclaration
2015 * en enumeration declaration to which will be added the
2018 * The high value of the range of the last enumerator
2019 * @return The high value of the value range of the current enumerator.
2020 * @throws ParseException
2022 private static long parseEnumEnumerator(CommonTree enumerator
,
2023 EnumDeclaration enumDeclaration
, long lastHigh
)
2024 throws ParseException
{
2026 List
<CommonTree
> children
= enumerator
.getChildren();
2028 long low
= 0, high
= 0;
2029 boolean valueSpecified
= false;
2030 String label
= null;
2032 for (CommonTree child
: children
) {
2033 if (isAnyUnaryString(child
)) {
2034 label
= parseUnaryString(child
);
2035 } else if (child
.getType() == CTFParser
.ENUM_VALUE
) {
2037 valueSpecified
= true;
2039 low
= parseUnaryInteger((CommonTree
) child
.getChild(0));
2041 } else if (child
.getType() == CTFParser
.ENUM_VALUE_RANGE
) {
2043 valueSpecified
= true;
2045 low
= parseUnaryInteger((CommonTree
) child
.getChild(0));
2046 high
= parseUnaryInteger((CommonTree
) child
.getChild(1));
2048 throw childTypeError(child
);
2052 if (!valueSpecified
) {
2058 throw new ParseException("enum low value greater than high value"); //$NON-NLS-1$
2061 if (!enumDeclaration
.add(low
, high
, label
)) {
2062 throw new ParseException("enum declarator values overlap."); //$NON-NLS-1$
2065 if (valueSpecified
&& (BigInteger
.valueOf(low
).compareTo(enumDeclaration
.getContainerType().getMinValue()) == -1 ||
2066 BigInteger
.valueOf(high
).compareTo(enumDeclaration
.getContainerType().getMaxValue()) == 1)) {
2067 throw new ParseException("enum value is not in range"); //$NON-NLS-1$
2074 * Parses an enum container type node and returns the corresponding integer
2077 * @param enumContainerType
2078 * An ENUM_CONTAINER_TYPE node.
2079 * @return An integer declaration corresponding to the container type.
2080 * @throws ParseException
2081 * If the type does not parse correctly or if it is not an
2084 private IntegerDeclaration
parseEnumContainerType(
2085 CommonTree enumContainerType
) throws ParseException
{
2087 /* Get the child, which should be a type specifier list */
2088 CommonTree typeSpecifierList
= (CommonTree
) enumContainerType
.getChild(0);
2090 /* Parse it and get the corresponding declaration */
2091 IDeclaration decl
= parseTypeSpecifierList(typeSpecifierList
);
2093 /* If is is an integer, return it, else throw an error */
2094 if (decl
instanceof IntegerDeclaration
) {
2095 return (IntegerDeclaration
) decl
;
2097 throw new ParseException("enum container type must be an integer"); //$NON-NLS-1$
2100 private VariantDeclaration
parseVariant(CommonTree variant
)
2101 throws ParseException
{
2103 List
<CommonTree
> children
= variant
.getChildren();
2104 VariantDeclaration variantDeclaration
= null;
2106 boolean hasName
= false;
2107 String variantName
= null;
2109 boolean hasBody
= false;
2110 CommonTree variantBody
= null;
2112 boolean hasTag
= false;
2113 String variantTag
= null;
2115 for (CommonTree child
: children
) {
2116 switch (child
.getType()) {
2117 case CTFParser
.VARIANT_NAME
:
2121 CommonTree variantNameIdentifier
= (CommonTree
) child
.getChild(0);
2123 variantName
= variantNameIdentifier
.getText();
2126 case CTFParser
.VARIANT_TAG
:
2130 CommonTree variantTagIdentifier
= (CommonTree
) child
.getChild(0);
2132 variantTag
= variantTagIdentifier
.getText();
2135 case CTFParser
.VARIANT_BODY
:
2139 variantBody
= child
;
2143 throw childTypeError(child
);
2149 * If variant has a name, check if already defined in the current
2153 && (getCurrentScope().lookupVariant(variantName
) != null)) {
2154 throw new ParseException("variant " + variantName
//$NON-NLS-1$
2155 + " already defined."); //$NON-NLS-1$
2158 /* Create the declaration */
2159 variantDeclaration
= new VariantDeclaration();
2161 /* Parse the body */
2162 parseVariantBody(variantBody
, variantDeclaration
, variantName
);
2164 /* If variant has name, add it to the current scope. */
2166 getCurrentScope().registerVariant(variantName
,
2167 variantDeclaration
);
2169 } else /* !hasBody */ {
2171 /* Name and !body */
2173 /* Lookup the name in the current scope. */
2174 variantDeclaration
= getCurrentScope().lookupVariantRecursive(
2178 * If not found, it means that a struct with such name has not
2181 if (variantDeclaration
== null) {
2182 throw new ParseException("variant " + variantName
//$NON-NLS-1$
2183 + " is not defined"); //$NON-NLS-1$
2186 /* !Name and !body */
2188 /* We can't do anything with that. */
2189 throw new ParseException("variant with no name and no body"); //$NON-NLS-1$
2194 variantDeclaration
.setTag(variantTag
);
2196 IDeclaration decl
= getCurrentScope().lookupIdentifierRecursive(variantTag
);
2198 throw new ParseException("Variant tag not found: " + variantTag
); //$NON-NLS-1$
2200 if (!(decl
instanceof EnumDeclaration
)) {
2201 throw new ParseException("Variant tag must be an enum: " + variantTag
); //$NON-NLS-1$
2203 EnumDeclaration tagDecl
= (EnumDeclaration
) decl
;
2204 Set
<String
> intersection
= new HashSet
<>(tagDecl
.getLabels());
2205 intersection
.retainAll(variantDeclaration
.getFields().keySet());
2206 if (intersection
.isEmpty()) {
2207 throw new ParseException("Variant contains no values of the tag, impossible to use: " + variantName
); //$NON-NLS-1$
2211 return variantDeclaration
;
2214 private void parseVariantBody(CommonTree variantBody
,
2215 VariantDeclaration variantDeclaration
, @Nullable String variantName
) throws ParseException
{
2217 List
<CommonTree
> variantDeclarations
= variantBody
.getChildren();
2219 pushNamedScope(variantName
, MetadataStrings
.VARIANT
);
2221 for (CommonTree declarationNode
: variantDeclarations
) {
2222 switch (declarationNode
.getType()) {
2223 case CTFParser
.TYPEALIAS
:
2224 parseTypealias(declarationNode
);
2226 case CTFParser
.TYPEDEF
:
2227 Map
<String
, IDeclaration
> decs
= parseTypedef(declarationNode
);
2228 for (Entry
<String
, IDeclaration
> declarationEntry
: decs
.entrySet()) {
2229 variantDeclaration
.addField(declarationEntry
.getKey(), declarationEntry
.getValue());
2232 case CTFParser
.SV_DECLARATION
:
2233 parseVariantDeclaration(declarationNode
, variantDeclaration
);
2236 throw childTypeError(declarationNode
);
2243 private void parseVariantDeclaration(CommonTree declaration
,
2244 VariantDeclaration variant
) throws ParseException
{
2246 /* Get the type specifier list node */
2247 CommonTree typeSpecifierListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_SPECIFIER_LIST
);
2249 /* Get the type declarator list node */
2250 CommonTree typeDeclaratorListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_DECLARATOR_LIST
);
2252 /* Get the type declarator list */
2253 List
<CommonTree
> typeDeclaratorList
= typeDeclaratorListNode
.getChildren();
2256 * For each type declarator, parse the declaration and add a field to
2259 for (CommonTree typeDeclaratorNode
: typeDeclaratorList
) {
2261 StringBuilder identifierSB
= new StringBuilder();
2263 IDeclaration decl
= parseTypeDeclarator(typeDeclaratorNode
,
2264 typeSpecifierListNode
, identifierSB
);
2266 String name
= identifierSB
.toString();
2268 if (variant
.hasField(name
)) {
2269 throw new ParseException("variant: duplicate field " //$NON-NLS-1$
2273 getCurrentScope().registerIdentifier(name
, decl
);
2275 variant
.addField(name
, decl
);
2280 * Creates the string representation of a type declaration (type specifier
2283 * @param typeSpecifierList
2284 * A TYPE_SPECIFIER_LIST node.
2286 * A list of POINTER nodes.
2287 * @return The string representation.
2288 * @throws ParseException
2290 private static String
createTypeDeclarationString(
2291 CommonTree typeSpecifierList
, List
<CommonTree
> pointers
)
2292 throws ParseException
{
2293 StringBuilder sb
= new StringBuilder();
2295 createTypeSpecifierListString(typeSpecifierList
, sb
);
2296 createPointerListString(pointers
, sb
);
2298 return sb
.toString();
2302 * Creates the string representation of a list of type specifiers.
2304 * @param typeSpecifierList
2305 * A TYPE_SPECIFIER_LIST node.
2307 * A StringBuilder to which will be appended the string.
2308 * @throws ParseException
2310 private static void createTypeSpecifierListString(
2311 CommonTree typeSpecifierList
, StringBuilder sb
)
2312 throws ParseException
{
2314 List
<CommonTree
> children
= typeSpecifierList
.getChildren();
2316 boolean firstItem
= true;
2318 for (CommonTree child
: children
) {
2326 /* Append the string that represents this type specifier. */
2327 createTypeSpecifierString(child
, sb
);
2332 * Creates the string representation of a type specifier.
2334 * @param typeSpecifier
2335 * A TYPE_SPECIFIER node.
2337 * A StringBuilder to which will be appended the string.
2338 * @throws ParseException
2340 private static void createTypeSpecifierString(CommonTree typeSpecifier
,
2341 StringBuilder sb
) throws ParseException
{
2342 switch (typeSpecifier
.getType()) {
2343 case CTFParser
.FLOATTOK
:
2344 case CTFParser
.INTTOK
:
2345 case CTFParser
.LONGTOK
:
2346 case CTFParser
.SHORTTOK
:
2347 case CTFParser
.SIGNEDTOK
:
2348 case CTFParser
.UNSIGNEDTOK
:
2349 case CTFParser
.CHARTOK
:
2350 case CTFParser
.DOUBLETOK
:
2351 case CTFParser
.VOIDTOK
:
2352 case CTFParser
.BOOLTOK
:
2353 case CTFParser
.COMPLEXTOK
:
2354 case CTFParser
.IMAGINARYTOK
:
2355 case CTFParser
.CONSTTOK
:
2356 case CTFParser
.IDENTIFIER
:
2357 sb
.append(typeSpecifier
.getText());
2359 case CTFParser
.STRUCT
: {
2360 CommonTree structName
= (CommonTree
) typeSpecifier
.getFirstChildWithType(CTFParser
.STRUCT_NAME
);
2361 if (structName
== null) {
2362 throw new ParseException("nameless struct found in createTypeSpecifierString"); //$NON-NLS-1$
2365 CommonTree structNameIdentifier
= (CommonTree
) structName
.getChild(0);
2367 sb
.append(structNameIdentifier
.getText());
2370 case CTFParser
.VARIANT
: {
2371 CommonTree variantName
= (CommonTree
) typeSpecifier
.getFirstChildWithType(CTFParser
.VARIANT_NAME
);
2372 if (variantName
== null) {
2373 throw new ParseException("nameless variant found in createTypeSpecifierString"); //$NON-NLS-1$
2376 CommonTree variantNameIdentifier
= (CommonTree
) variantName
.getChild(0);
2378 sb
.append(variantNameIdentifier
.getText());
2381 case CTFParser
.ENUM
: {
2382 CommonTree enumName
= (CommonTree
) typeSpecifier
.getFirstChildWithType(CTFParser
.ENUM_NAME
);
2383 if (enumName
== null) {
2384 throw new ParseException("nameless enum found in createTypeSpecifierString"); //$NON-NLS-1$
2387 CommonTree enumNameIdentifier
= (CommonTree
) enumName
.getChild(0);
2389 sb
.append(enumNameIdentifier
.getText());
2392 case CTFParser
.FLOATING_POINT
:
2393 case CTFParser
.INTEGER
:
2394 case CTFParser
.STRING
:
2395 throw new ParseException("CTF type found in createTypeSpecifierString"); //$NON-NLS-1$
2397 throw childTypeError(typeSpecifier
);
2402 * Creates the string representation of a list of pointers.
2404 * @param pointerList
2405 * A list of pointer nodes. If pointerList is null, this function
2408 * A stringbuilder to which will be appended the string.
2410 private static void createPointerListString(List
<CommonTree
> pointerList
,
2412 if (pointerList
== null) {
2416 for (CommonTree pointer
: pointerList
) {
2418 sb
.append(" *"); //$NON-NLS-1$
2419 if (pointer
.getChildCount() > 0) {
2421 sb
.append(" const"); //$NON-NLS-1$
2428 * The node to check.
2429 * @return True if the given node is an unary string.
2431 private static boolean isUnaryString(CommonTree node
) {
2432 return ((node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING
));
2437 * The node to check.
2438 * @return True if the given node is any type of unary string (no quotes,
2441 private static boolean isAnyUnaryString(CommonTree node
) {
2442 return ((node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING
) || (node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING_QUOTES
));
2447 * The node to check.
2448 * @return True if the given node is an unary integer.
2450 private static boolean isUnaryInteger(CommonTree node
) {
2451 return ((node
.getType() == CTFParser
.UNARY_EXPRESSION_DEC
) ||
2452 (node
.getType() == CTFParser
.UNARY_EXPRESSION_HEX
) || (node
.getType() == CTFParser
.UNARY_EXPRESSION_OCT
));
2456 * Parses a unary string node and return the string value.
2458 * @param unaryString
2459 * The unary string node to parse (type UNARY_EXPRESSION_STRING
2460 * or UNARY_EXPRESSION_STRING_QUOTES).
2461 * @return The string value.
2464 * It would be really nice to remove the quotes earlier, such as in the
2467 private static String
parseUnaryString(CommonTree unaryString
) {
2469 CommonTree value
= (CommonTree
) unaryString
.getChild(0);
2470 if (value
.getType() == CTFParser
.UNARY_EXPRESSION_STRING
) {
2471 value
= (CommonTree
) value
.getChild(0);
2473 String strval
= value
.getText();
2476 if (unaryString
.getType() == CTFParser
.UNARY_EXPRESSION_STRING_QUOTES
) {
2477 strval
= strval
.substring(1, strval
.length() - 1);
2484 * Parses an unary integer (dec, hex or oct).
2486 * @param unaryInteger
2487 * An unary integer node.
2488 * @return The integer value.
2489 * @throws ParseException
2490 * on an invalid integer format ("bob" for example)
2492 private static long parseUnaryInteger(CommonTree unaryInteger
) throws ParseException
{
2494 List
<CommonTree
> children
= unaryInteger
.getChildren();
2495 CommonTree value
= children
.get(0);
2496 String strval
= value
.getText();
2500 intval
= Long
.decode(strval
);
2501 } catch (NumberFormatException e
) {
2502 throw new ParseException("Invalid integer format: " + strval
, e
); //$NON-NLS-1$
2505 /* The rest of children are sign */
2506 if ((children
.size() % 2) == 0) {
2512 private static long getMajorOrMinor(CommonTree rightNode
)
2513 throws ParseException
{
2515 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2517 if (isUnaryInteger(firstChild
)) {
2518 if (rightNode
.getChildCount() > 1) {
2519 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2522 long m
= parseUnaryInteger(firstChild
);
2525 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2530 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2533 private static UUID
getUUID(CommonTree rightNode
) throws ParseException
{
2535 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2537 if (isAnyUnaryString(firstChild
)) {
2538 if (rightNode
.getChildCount() > 1) {
2539 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2542 String uuidstr
= parseUnaryString(firstChild
);
2545 return UUID
.fromString(uuidstr
);
2546 } catch (IllegalArgumentException e
) {
2547 throw new ParseException("Invalid format for UUID", e
); //$NON-NLS-1$
2550 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2554 * Gets the value of a "signed" integer attribute.
2558 * @return The "signed" value as a boolean.
2559 * @throws ParseException
2561 private static boolean getSigned(CommonTree rightNode
)
2562 throws ParseException
{
2564 boolean ret
= false;
2565 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2567 if (isUnaryString(firstChild
)) {
2568 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
2570 if (strval
.equals(MetadataStrings
.TRUE
)
2571 || strval
.equals(MetadataStrings
.TRUE2
)) {
2573 } else if (strval
.equals(MetadataStrings
.FALSE
)
2574 || strval
.equals(MetadataStrings
.FALSE2
)) {
2577 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2578 + firstChild
.getChild(0).getText());
2580 } else if (isUnaryInteger(firstChild
)) {
2581 /* Happens if the value is something like "1234.hello" */
2582 if (rightNode
.getChildCount() > 1) {
2583 throw new ParseException("Invalid boolean value"); //$NON-NLS-1$
2586 long intval
= parseUnaryInteger(firstChild
);
2590 } else if (intval
== 0) {
2593 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2594 + firstChild
.getChild(0).getText());
2597 throw new ParseException();
2604 * Gets the value of a "byte_order" integer attribute.
2608 * @return The "byte_order" value.
2609 * @throws ParseException
2611 private ByteOrder
getByteOrder(CommonTree rightNode
) throws ParseException
{
2613 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2615 if (isUnaryString(firstChild
)) {
2616 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
2618 if (strval
.equals(MetadataStrings
.LE
)) {
2619 return ByteOrder
.LITTLE_ENDIAN
;
2620 } else if (strval
.equals(MetadataStrings
.BE
)
2621 || strval
.equals(MetadataStrings
.NETWORK
)) {
2622 return ByteOrder
.BIG_ENDIAN
;
2623 } else if (strval
.equals(MetadataStrings
.NATIVE
)) {
2624 return fTrace
.getByteOrder();
2626 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2629 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2633 * Determines if the given value is a valid alignment value.
2636 * The value to check.
2637 * @return True if it is valid.
2639 private static boolean isValidAlignment(long alignment
) {
2640 return !((alignment
<= 0) || ((alignment
& (alignment
- 1)) != 0));
2644 * Gets the value of a "size" integer attribute.
2648 * @return The "size" value.
2649 * @throws ParseException
2651 private static long getSize(CommonTree rightNode
) throws ParseException
{
2653 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2655 if (isUnaryInteger(firstChild
)) {
2656 if (rightNode
.getChildCount() > 1) {
2657 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2660 long size
= parseUnaryInteger(firstChild
);
2663 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2668 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2672 * Gets the value of a "align" integer or struct attribute.
2675 * A CTF_RIGHT node or directly an unary integer.
2676 * @return The align value.
2677 * @throws ParseException
2679 private static long getAlignment(CommonTree node
) throws ParseException
{
2682 * If a CTF_RIGHT node was passed, call getAlignment with the first
2685 if (node
.getType() == CTFParser
.CTF_RIGHT
) {
2686 if (node
.getChildCount() > 1) {
2687 throw new ParseException("Invalid alignment value"); //$NON-NLS-1$
2690 return getAlignment((CommonTree
) node
.getChild(0));
2691 } else if (isUnaryInteger(node
)) {
2692 long alignment
= parseUnaryInteger(node
);
2694 if (!isValidAlignment(alignment
)) {
2695 throw new ParseException("Invalid value for alignment : " //$NON-NLS-1$
2701 throw new ParseException("Invalid value for alignment"); //$NON-NLS-1$
2705 * Gets the value of a "base" integer attribute.
2708 * An CTF_RIGHT node.
2709 * @return The "base" value.
2710 * @throws ParseException
2712 private static int getBase(CommonTree rightNode
) throws ParseException
{
2714 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2716 if (isUnaryInteger(firstChild
)) {
2717 if (rightNode
.getChildCount() > 1) {
2718 throw new ParseException("invalid base value"); //$NON-NLS-1$
2721 long intval
= parseUnaryInteger(firstChild
);
2722 if ((intval
== INTEGER_BASE_2
) || (intval
== INTEGER_BASE_8
) || (intval
== INTEGER_BASE_10
)
2723 || (intval
== INTEGER_BASE_16
)) {
2724 return (int) intval
;
2726 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2727 } else if (isUnaryString(firstChild
)) {
2728 switch (concatenateUnaryStrings(rightNode
.getChildren())) {
2729 case MetadataStrings
.DECIMAL
:
2730 case MetadataStrings
.DEC
:
2731 case MetadataStrings
.DEC_CTE
:
2732 case MetadataStrings
.INT_MOD
:
2733 case MetadataStrings
.UNSIGNED_CTE
:
2734 return INTEGER_BASE_10
;
2735 case MetadataStrings
.HEXADECIMAL
:
2736 case MetadataStrings
.HEX
:
2737 case MetadataStrings
.X
:
2738 case MetadataStrings
.X2
:
2739 case MetadataStrings
.POINTER
:
2740 return INTEGER_BASE_16
;
2741 case MetadataStrings
.OCT
:
2742 case MetadataStrings
.OCTAL
:
2743 case MetadataStrings
.OCTAL_CTE
:
2744 return INTEGER_BASE_8
;
2745 case MetadataStrings
.BIN
:
2746 case MetadataStrings
.BINARY
:
2747 return INTEGER_BASE_2
;
2749 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2752 throw new ParseException("invalid value for base"); //$NON-NLS-1$
2757 * Gets the value of an "encoding" integer attribute.
2761 * @return The "encoding" value.
2762 * @throws ParseException
2765 private static Encoding
getEncoding(CommonTree rightNode
)
2766 throws ParseException
{
2768 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2770 if (isUnaryString(firstChild
)) {
2771 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
2773 if (strval
.equals(MetadataStrings
.UTF8
)) {
2774 return Encoding
.UTF8
;
2775 } else if (strval
.equals(MetadataStrings
.ASCII
)) {
2776 return Encoding
.ASCII
;
2777 } else if (strval
.equals(MetadataStrings
.NONE
)) {
2778 return Encoding
.NONE
;
2780 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2783 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2786 private static long getStreamID(CommonTree rightNode
) throws ParseException
{
2788 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2790 if (isUnaryInteger(firstChild
)) {
2791 if (rightNode
.getChildCount() > 1) {
2792 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2795 long intval
= parseUnaryInteger(firstChild
);
2799 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2802 private static String
getEventName(CommonTree rightNode
)
2803 throws ParseException
{
2805 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2807 if (isAnyUnaryString(firstChild
)) {
2808 String str
= concatenateUnaryStrings(rightNode
.getChildren());
2812 throw new ParseException("invalid value for event name"); //$NON-NLS-1$
2815 private static long getEventID(CommonTree rightNode
) throws ParseException
{
2817 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2819 if (isUnaryInteger(firstChild
)) {
2820 if (rightNode
.getChildCount() > 1) {
2821 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2824 long intval
= parseUnaryInteger(firstChild
);
2825 if (intval
> Integer
.MAX_VALUE
) {
2826 throw new ParseException("Event id larger than int.maxvalue, something is amiss"); //$NON-NLS-1$
2830 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2834 * Concatenates a list of unary strings separated by arrows (->) or dots.
2837 * A list, first element being an unary string, subsequent
2838 * elements being ARROW or DOT nodes with unary strings as child.
2839 * @return The string representation of the unary string chain.
2841 private static String
concatenateUnaryStrings(List
<CommonTree
> strings
) {
2843 StringBuilder sb
= new StringBuilder();
2845 CommonTree first
= strings
.get(0);
2846 sb
.append(parseUnaryString(first
));
2848 boolean isFirst
= true;
2850 for (CommonTree ref
: strings
) {
2856 CommonTree id
= (CommonTree
) ref
.getChild(0);
2858 if (ref
.getType() == CTFParser
.ARROW
) {
2859 sb
.append("->"); //$NON-NLS-1$
2864 sb
.append(parseUnaryString(id
));
2867 return sb
.toString();
2871 * Throws a ParseException stating that the parent-child relation between
2872 * the given node and its parent is not valid. It means that the shape of
2873 * the AST is unexpected.
2876 * The invalid child node.
2877 * @return ParseException with details
2879 private static ParseException
childTypeError(CommonTree child
) {
2880 CommonTree parent
= (CommonTree
) child
.getParent();
2881 String error
= "Parent " + CTFParser
.tokenNames
[parent
.getType()] //$NON-NLS-1$
2882 + " can't have a child of type " //$NON-NLS-1$
2883 + CTFParser
.tokenNames
[child
.getType()] + "."; //$NON-NLS-1$
2885 return new ParseException(error
);
2888 // ------------------------------------------------------------------------
2890 // ------------------------------------------------------------------------
2893 * Adds a new declaration scope on the top of the scope stack.
2895 private void pushScope(String name
) {
2896 fScope
= new DeclarationScope(getCurrentScope(), name
);
2900 * Removes the top declaration scope from the scope stack.
2902 private void popScope() {
2903 fScope
= getCurrentScope().getParentScope();
2906 private void pushNamedScope(@Nullable String name
, String defaultName
) {
2907 pushScope(name
== null ? defaultName
: name
);
2911 * Returns the current declaration scope.
2913 * @return The current declaration scope.
2915 private DeclarationScope
getCurrentScope() {