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
.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
;
60 import com
.google
.common
.collect
.Iterables
;
65 public class IOStructGen
{
67 // ------------------------------------------------------------------------
69 // ------------------------------------------------------------------------
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;
88 private final CTFTrace fTrace
;
89 private CommonTree fTree
;
92 * The current declaration scope.
94 private final DeclarationScope fRoot
;
95 private DeclarationScope fScope
;
98 * Data helpers needed for streaming
101 private boolean fHasBeenParsed
= false;
103 // ------------------------------------------------------------------------
105 // ------------------------------------------------------------------------
111 * the tree (ANTLR generated) with the parsed TSDL data.
113 * the trace containing the places to put all the read metadata
115 public IOStructGen(CommonTree tree
, CTFTrace trace
) {
118 fRoot
= trace
.getScope();
123 * Parse the tree and populate the trace defined in the constructor.
125 * @throws ParseException
126 * If there was a problem parsing the metadata
128 public void generate() throws ParseException
{
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
137 * @throws ParseException
138 * If there was a problem parsing the metadata
140 public void generateFragment() throws ParseException
{
141 parseIncompleteRoot(fTree
);
144 // ------------------------------------------------------------------------
146 // ------------------------------------------------------------------------
149 * Sets a new tree to parse
152 * the new tree to parse
154 public void setTree(CommonTree newTree
) {
159 * Parse the root node.
163 * @throws ParseException
165 private void parseRoot(CommonTree root
) throws ParseException
{
167 List
<CommonTree
> children
= root
.getChildren();
169 CommonTree traceNode
= null;
170 boolean hasStreams
= false;
171 List
<CommonTree
> events
= new ArrayList
<>();
173 for (CommonTree child
: children
) {
174 final int type
= child
.getType();
176 case CTFParser
.DECLARATION
:
177 parseRootDeclaration(child
);
179 case CTFParser
.TRACE
:
180 if (traceNode
!= null) {
181 throw new ParseException("Only one trace block is allowed"); //$NON-NLS-1$
184 parseTrace(traceNode
);
186 case CTFParser
.STREAM
:
190 case CTFParser
.EVENT
:
193 case CTFParser
.CLOCK
:
197 parseEnvironment(child
);
200 throw childTypeError(child
);
203 if (traceNode
== null) {
204 throw new ParseException("Missing trace block"); //$NON-NLS-1$
206 parseEvents(events
, hasStreams
);
208 fHasBeenParsed
= true;
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
));
216 for (CommonTree event
: events
) {
221 private void parseIncompleteRoot(CommonTree root
) throws ParseException
{
222 if (!fHasBeenParsed
) {
223 throw new ParseException("You need to run generate first"); //$NON-NLS-1$
225 List
<CommonTree
> children
= root
.getChildren();
226 List
<CommonTree
> events
= new ArrayList
<>();
228 for (CommonTree child
: children
) {
229 final int type
= child
.getType();
231 case CTFParser
.DECLARATION
:
232 parseRootDeclaration(child
);
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
:
239 case CTFParser
.EVENT
:
242 case CTFParser
.CLOCK
:
246 parseEnvironment(child
);
249 throw childTypeError(child
);
252 parseEvents(events
, !Iterables
.isEmpty(fTrace
.getStreams()));
256 private void resetScope() {
260 private void parseEnvironment(CommonTree environment
) {
261 List
<CommonTree
> children
= environment
.getChildren();
262 for (CommonTree child
: children
) {
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
);
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();
280 case CTFParser
.INTEGER
:
281 case CTFParser
.DECIMAL_LITERAL
:
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
294 numValue
= Long
.parseLong(text
);
295 } catch (NumberFormatException e
) {
296 throw new ParseException("Number conversion issue with " + text
, e
); //$NON-NLS-1$
298 ctfClock
.addAttribute(key
, numValue
);
301 ctfClock
.addAttribute(key
, text
);
305 String nameValue
= ctfClock
.getName();
306 fTrace
.addClock(nameValue
, ctfClock
);
309 private void parseTrace(CommonTree traceNode
) throws ParseException
{
311 List
<CommonTree
> children
= traceNode
.getChildren();
312 if (children
== null) {
313 throw new ParseException("Trace block is empty"); //$NON-NLS-1$
318 for (CommonTree child
: children
) {
319 switch (child
.getType()) {
320 case CTFParser
.TYPEALIAS
:
321 parseTypealias(child
);
323 case CTFParser
.TYPEDEF
:
326 case CTFParser
.CTF_EXPRESSION_TYPE
:
327 case CTFParser
.CTF_EXPRESSION_VAL
:
328 parseTraceDeclaration(child
);
331 throw childTypeError(child
);
336 * If trace byte order was not specified and not using packet based
339 if (fTrace
.getByteOrder() == null) {
340 throw new ParseException("Trace byte order not set"); //$NON-NLS-1$
344 private void parseTraceDeclaration(CommonTree traceDecl
)
345 throws ParseException
{
347 /* There should be a left and right */
349 CommonTree leftNode
= (CommonTree
) traceDecl
.getChild(0);
350 CommonTree rightNode
= (CommonTree
) traceDecl
.getChild(1);
352 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
354 if (!isAnyUnaryString(leftStrings
.get(0))) {
355 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
358 String left
= concatenateUnaryStrings(leftStrings
);
360 if (left
.equals(MetadataStrings
.MAJOR
)) {
361 if (fTrace
.majorIsSet()) {
362 throw new ParseException("major is already set"); //$NON-NLS-1$
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$
371 fTrace
.setMinor(getMajorOrMinor(rightNode
));
372 } else if (left
.equals(MetadataStrings
.UUID_STRING
)) {
373 UUID uuid
= getUUID(rightNode
);
376 * If uuid was already set by a metadata packet, compare it to see
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$
385 fTrace
.setUUID(uuid
);
388 } else if (left
.equals(MetadataStrings
.BYTE_ORDER
)) {
389 ByteOrder byteOrder
= getByteOrder(rightNode
);
392 * If byte order was already set by a metadata packet, compare it to
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$
403 fTrace
.setByteOrder(byteOrder
);
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
);
419 } else if (left
.equals(MetadataStrings
.PACKET_HEADER
)) {
420 if (fTrace
.packetHeaderIsSet()) {
421 throw new ParseException("packet.header already defined"); //$NON-NLS-1$
424 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
426 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
427 throw new ParseException("packet.header expects a type specifier"); //$NON-NLS-1$
430 IDeclaration packetHeaderDecl
= parseTypeSpecifierList(typeSpecifier
);
432 if (!(packetHeaderDecl
instanceof StructDeclaration
)) {
433 throw new ParseException("packet.header expects a struct"); //$NON-NLS-1$
436 fTrace
.setPacketHeader((StructDeclaration
) packetHeaderDecl
);
438 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownTraceAttributeWarning
+ " " + left
); //$NON-NLS-1$
442 private static void addByteOrder(ByteOrder byteOrder
,
443 final DeclarationScope parentScope
, String name
,
444 IntegerDeclaration decl
) throws ParseException
{
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
);
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());
465 parentScope
.replaceType(name
, newEnum
);
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
);
476 private void setAlign(DeclarationScope parentScope
, StructDeclaration sd
,
477 ByteOrder byteOrder
) throws ParseException
{
479 for (String s
: sd
.getFieldsList()) {
480 IDeclaration d
= sd
.getField(s
);
482 if (d
instanceof StructDeclaration
) {
483 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
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
);
501 private void setAlign(DeclarationScope parentScope
, VariantDeclaration vd
,
502 ByteOrder byteOrder
) throws ParseException
{
504 for (String s
: vd
.getFields().keySet()) {
505 IDeclaration d
= vd
.getFields().get(s
);
507 if (d
instanceof StructDeclaration
) {
508 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
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
);
522 private void parseStream(CommonTree streamNode
) throws ParseException
{
524 CTFStream stream
= new CTFStream(fTrace
);
526 List
<CommonTree
> children
= streamNode
.getChildren();
527 if (children
== null) {
528 throw new ParseException("Empty stream block"); //$NON-NLS-1$
531 pushScope(MetadataStrings
.STREAM
);
533 for (CommonTree child
: children
) {
534 switch (child
.getType()) {
535 case CTFParser
.TYPEALIAS
:
536 parseTypealias(child
);
538 case CTFParser
.TYPEDEF
:
541 case CTFParser
.CTF_EXPRESSION_TYPE
:
542 case CTFParser
.CTF_EXPRESSION_VAL
:
543 parseStreamDeclaration(child
, stream
);
546 throw childTypeError(child
);
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$
555 fTrace
.addStream(stream
);
560 private void parseStreamDeclaration(CommonTree streamDecl
, CTFStream stream
)
561 throws ParseException
{
563 /* There should be a left and right */
565 CommonTree leftNode
= (CommonTree
) streamDecl
.getChild(0);
566 CommonTree rightNode
= (CommonTree
) streamDecl
.getChild(1);
568 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
570 if (!isAnyUnaryString(leftStrings
.get(0))) {
571 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
574 String left
= concatenateUnaryStrings(leftStrings
);
576 if (left
.equals(MetadataStrings
.ID
)) {
577 if (stream
.isIdSet()) {
578 throw new ParseException("stream id already defined"); //$NON-NLS-1$
581 long streamID
= getStreamID(rightNode
);
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$
589 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
591 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
592 throw new ParseException("event.header expects a type specifier"); //$NON-NLS-1$
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$
601 pushScope(MetadataStrings
.EVENT
);
602 getCurrentScope().addChild(eventHeaderScope
);
603 eventHeaderScope
.setName(CTFStrings
.HEADER
);
605 if (eventHeaderDecl
instanceof StructDeclaration
) {
606 stream
.setEventHeader((StructDeclaration
) eventHeaderDecl
);
607 } else if (eventHeaderDecl
instanceof IEventHeaderDeclaration
) {
608 stream
.setEventHeader((IEventHeaderDeclaration
) eventHeaderDecl
);
610 throw new ParseException("event.header expects a struct"); //$NON-NLS-1$
613 } else if (left
.equals(MetadataStrings
.EVENT_CONTEXT
)) {
614 if (stream
.isEventContextSet()) {
615 throw new ParseException("event.context already defined"); //$NON-NLS-1$
618 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
620 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
621 throw new ParseException("event.context expects a type specifier"); //$NON-NLS-1$
624 IDeclaration eventContextDecl
= parseTypeSpecifierList(typeSpecifier
);
626 if (!(eventContextDecl
instanceof StructDeclaration
)) {
627 throw new ParseException("event.context expects a struct"); //$NON-NLS-1$
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$
636 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
638 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
639 throw new ParseException("packet.context expects a type specifier"); //$NON-NLS-1$
642 IDeclaration packetContextDecl
= parseTypeSpecifierList(typeSpecifier
);
644 if (!(packetContextDecl
instanceof StructDeclaration
)) {
645 throw new ParseException("packet.context expects a struct"); //$NON-NLS-1$
648 stream
.setPacketContext((StructDeclaration
) packetContextDecl
);
650 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownStreamAttributeWarning
+ " " + left
); //$NON-NLS-1$
654 private static DeclarationScope
lookupStructName(CommonTree typeSpecifier
, DeclarationScope scope
) {
656 * This needs a struct.struct_name.name to work, luckily, that is 99.99%
657 * of traces we receive.
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
);
669 * If that fails, maybe the struct is anonymous
671 if (eventHeaderScope
== null) {
672 eventHeaderScope
= scope
.lookupChildRecursive(MetadataStrings
.STRUCT
);
675 * This can still be null
677 return eventHeaderScope
;
680 private void parseEvent(CommonTree eventNode
) throws ParseException
{
682 List
<CommonTree
> children
= eventNode
.getChildren();
683 if (children
== null) {
684 throw new ParseException("Empty event block"); //$NON-NLS-1$
687 EventDeclaration event
= new EventDeclaration();
689 pushScope(MetadataStrings
.EVENT
);
691 for (CommonTree child
: children
) {
692 switch (child
.getType()) {
693 case CTFParser
.TYPEALIAS
:
694 parseTypealias(child
);
696 case CTFParser
.TYPEDEF
:
699 case CTFParser
.CTF_EXPRESSION_TYPE
:
700 case CTFParser
.CTF_EXPRESSION_VAL
:
701 parseEventDeclaration(child
, event
);
704 throw childTypeError(child
);
708 if (!event
.nameIsSet()) {
709 throw new ParseException("Event name not set"); //$NON-NLS-1$
713 * If the event did not specify a stream, then the trace must be single
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$
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
727 CTFStream stream
= fTrace
.getStream(null);
729 if (stream
!= null) {
730 event
.setStream(stream
);
732 throw new ParseException("Event without stream_id, but there is no stream without id"); //$NON-NLS-1$
737 * Add the event to the stream.
739 event
.getStream().addEvent(event
);
744 private void parseEventDeclaration(CommonTree eventDecl
,
745 EventDeclaration event
) throws ParseException
{
747 /* There should be a left and right */
749 CommonTree leftNode
= (CommonTree
) eventDecl
.getChild(0);
750 CommonTree rightNode
= (CommonTree
) eventDecl
.getChild(1);
752 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
754 if (!isAnyUnaryString(leftStrings
.get(0))) {
755 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
758 String left
= concatenateUnaryStrings(leftStrings
);
760 if (left
.equals(MetadataStrings
.NAME2
)) {
761 if (event
.nameIsSet()) {
762 throw new ParseException("name already defined"); //$NON-NLS-1$
765 String name
= getEventName(rightNode
);
768 } else if (left
.equals(MetadataStrings
.ID
)) {
769 if (event
.idIsSet()) {
770 throw new ParseException("id already defined"); //$NON-NLS-1$
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$
778 throw new ParseException("negative id, unsupported. id : " + id
); //$NON-NLS-1$
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$
786 long streamId
= getStreamID(rightNode
);
788 CTFStream stream
= fTrace
.getStream(streamId
);
790 if (stream
== null) {
791 throw new ParseException("Stream " + streamId
+ " not found"); //$NON-NLS-1$ //$NON-NLS-2$
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$
800 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
802 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
803 throw new ParseException("context expects a type specifier"); //$NON-NLS-1$
806 IDeclaration contextDecl
= parseTypeSpecifierList(typeSpecifier
);
808 if (!(contextDecl
instanceof StructDeclaration
)) {
809 throw new ParseException("context expects a struct"); //$NON-NLS-1$
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$
818 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
820 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
821 throw new ParseException("fields expects a type specifier"); //$NON-NLS-1$
824 IDeclaration fieldsDecl
;
825 fieldsDecl
= parseTypeSpecifierList(typeSpecifier
);
827 if (!(fieldsDecl
instanceof StructDeclaration
)) {
828 throw new ParseException("fields expects a struct"); //$NON-NLS-1$
831 * The underscores in the event names. These underscores were added
832 * by the LTTng tracer.
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
);
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
);
847 * Parses a declaration at the root level.
850 * The declaration subtree.
851 * @throws ParseException
853 private void parseRootDeclaration(CommonTree declaration
)
854 throws ParseException
{
856 List
<CommonTree
> children
= declaration
.getChildren();
858 for (CommonTree child
: children
) {
859 switch (child
.getType()) {
860 case CTFParser
.TYPEDEF
:
863 case CTFParser
.TYPEALIAS
:
864 parseTypealias(child
);
866 case CTFParser
.TYPE_SPECIFIER_LIST
:
867 parseTypeSpecifierList(child
);
870 throw childTypeError(child
);
876 * Parses a typealias node. It parses the target, the alias, and registers
877 * the type in the current scope.
881 * @throws ParseException
883 private void parseTypealias(CommonTree typealias
) throws ParseException
{
885 List
<CommonTree
> children
= typealias
.getChildren();
887 CommonTree target
= null;
888 CommonTree alias
= null;
890 for (CommonTree child
: children
) {
891 switch (child
.getType()) {
892 case CTFParser
.TYPEALIAS_TARGET
:
895 case CTFParser
.TYPEALIAS_ALIAS
:
899 throw childTypeError(child
);
903 IDeclaration targetDeclaration
= parseTypealiasTarget(target
);
905 if ((targetDeclaration
instanceof VariantDeclaration
)
906 && ((VariantDeclaration
) targetDeclaration
).isTagged()) {
907 throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
910 String aliasString
= parseTypealiasAlias(alias
);
912 getCurrentScope().registerType(aliasString
, targetDeclaration
);
916 * Parses the target part of a typealias and gets the corresponding
920 * A TYPEALIAS_TARGET node.
921 * @return The corresponding declaration.
922 * @throws ParseException
924 private IDeclaration
parseTypealiasTarget(CommonTree target
)
925 throws ParseException
{
927 List
<CommonTree
> children
= target
.getChildren();
929 CommonTree typeSpecifierList
= null;
930 CommonTree typeDeclaratorList
= null;
931 CommonTree typeDeclarator
= null;
932 StringBuilder identifierSB
= new StringBuilder();
934 for (CommonTree child
: children
) {
935 switch (child
.getType()) {
936 case CTFParser
.TYPE_SPECIFIER_LIST
:
937 typeSpecifierList
= child
;
939 case CTFParser
.TYPE_DECLARATOR_LIST
:
940 typeDeclaratorList
= child
;
943 throw childTypeError(child
);
947 if (typeDeclaratorList
!= null) {
949 * Only allow one declarator
951 * eg: "typealias uint8_t *, ** := puint8_t;" is not permitted,
952 * otherwise the new type puint8_t would maps to two different
955 if (typeDeclaratorList
.getChildCount() != 1) {
956 throw new ParseException("Only one type declarator is allowed in the typealias target"); //$NON-NLS-1$
959 typeDeclarator
= (CommonTree
) typeDeclaratorList
.getChild(0);
962 /* Parse the target type and get the declaration */
963 IDeclaration targetDeclaration
= parseTypeDeclarator(typeDeclarator
,
964 typeSpecifierList
, identifierSB
);
967 * We don't allow identifier in the target
969 * eg: "typealias uint8_t* hello := puint8_t;", the "hello" is not
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$
977 return targetDeclaration
;
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.
986 * A TYPEALIAS_ALIAS node.
987 * @return The string representation of the alias.
988 * @throws ParseException
990 private static String
parseTypealiasAlias(CommonTree alias
)
991 throws ParseException
{
993 List
<CommonTree
> children
= alias
.getChildren();
995 CommonTree typeSpecifierList
= null;
996 CommonTree typeDeclaratorList
= null;
997 CommonTree typeDeclarator
= null;
998 List
<CommonTree
> pointers
= new LinkedList
<>();
1000 for (CommonTree child
: children
) {
1001 switch (child
.getType()) {
1002 case CTFParser
.TYPE_SPECIFIER_LIST
:
1003 typeSpecifierList
= child
;
1005 case CTFParser
.TYPE_DECLARATOR_LIST
:
1006 typeDeclaratorList
= child
;
1009 throw childTypeError(child
);
1013 /* If there is a type declarator list, extract the pointers */
1014 if (typeDeclaratorList
!= null) {
1016 * Only allow one declarator
1018 * eg: "typealias uint8_t := puint8_t *, **;" is not permitted.
1020 if (typeDeclaratorList
.getChildCount() != 1) {
1021 throw new ParseException("Only one type declarator is allowed in the typealias alias"); //$NON-NLS-1$
1024 typeDeclarator
= (CommonTree
) typeDeclaratorList
.getChild(0);
1026 List
<CommonTree
> typeDeclaratorChildren
= typeDeclarator
.getChildren();
1028 for (CommonTree child
: typeDeclaratorChildren
) {
1029 switch (child
.getType()) {
1030 case CTFParser
.POINTER
:
1031 pointers
.add(child
);
1033 case CTFParser
.IDENTIFIER
:
1034 throw new ParseException("Identifier (" + child
.getText() //$NON-NLS-1$
1035 + ") not expected in the typealias target"); //$NON-NLS-1$
1037 throw childTypeError(child
);
1042 return createTypeDeclarationString(typeSpecifierList
, pointers
);
1046 * Parses a typedef node. This creates and registers a new declaration for
1047 * each declarator found in the typedef.
1051 * @return map of type name to type declaration
1052 * @throws ParseException
1053 * If there is an error creating the declaration.
1055 private Map
<String
, IDeclaration
> parseTypedef(CommonTree typedef
) throws ParseException
{
1057 CommonTree typeDeclaratorListNode
= (CommonTree
) typedef
.getFirstChildWithType(CTFParser
.TYPE_DECLARATOR_LIST
);
1059 CommonTree typeSpecifierListNode
= (CommonTree
) typedef
.getFirstChildWithType(CTFParser
.TYPE_SPECIFIER_LIST
);
1061 List
<CommonTree
> typeDeclaratorList
= typeDeclaratorListNode
.getChildren();
1063 Map
<String
, IDeclaration
> declarations
= new HashMap
<>();
1065 for (CommonTree typeDeclaratorNode
: typeDeclaratorList
) {
1066 StringBuilder identifierSB
= new StringBuilder();
1068 IDeclaration typeDeclaration
= parseTypeDeclarator(
1069 typeDeclaratorNode
, typeSpecifierListNode
, identifierSB
);
1071 if ((typeDeclaration
instanceof VariantDeclaration
)
1072 && !((VariantDeclaration
) typeDeclaration
).isTagged()) {
1073 throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
1076 getCurrentScope().registerType(identifierSB
.toString(),
1079 declarations
.put(identifierSB
.toString(), typeDeclaration
);
1081 return declarations
;
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}.
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
1096 * @return The corresponding declaration.
1097 * @throws ParseException
1098 * If there is an error finding or creating the declaration.
1100 private IDeclaration
parseTypeDeclarator(CommonTree typeDeclarator
,
1101 CommonTree typeSpecifierList
, StringBuilder identifierSB
)
1102 throws ParseException
{
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;
1110 /* Separate the tokens by type */
1111 if (typeDeclarator
!= null) {
1112 children
= typeDeclarator
.getChildren();
1113 for (CommonTree child
: children
) {
1115 switch (child
.getType()) {
1116 case CTFParser
.POINTER
:
1117 pointers
.add(child
);
1119 case CTFParser
.IDENTIFIER
:
1122 case CTFParser
.LENGTH
:
1126 throw childTypeError(child
);
1133 * Parse the type specifier list, which is the "base" type. For example,
1134 * it would be int in int a[3][len].
1136 declaration
= parseTypeSpecifierList(typeSpecifierList
, pointers
, identifier
);
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)).
1143 if (!lengths
.isEmpty()) {
1144 /* We begin at the end */
1145 Collections
.reverse(lengths
);
1147 for (CommonTree length
: lengths
) {
1149 * By looking at the first expression, we can determine whether
1150 * it is an array or a sequence.
1152 List
<CommonTree
> lengthChildren
= length
.getChildren();
1154 CommonTree first
= lengthChildren
.get(0);
1155 if (isUnaryInteger(first
)) {
1157 int arrayLength
= (int) parseUnaryInteger(first
);
1159 if (arrayLength
< 1) {
1160 throw new ParseException("Array length is negative"); //$NON-NLS-1$
1163 /* Create the array declaration. */
1164 declaration
= new ArrayDeclaration(arrayLength
, declaration
);
1165 } else if (isAnyUnaryString(first
)) {
1167 String lengthName
= concatenateUnaryStrings(lengthChildren
);
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$
1173 /* Create the sequence declaration. */
1174 declaration
= new SequenceDeclaration(lengthName
,
1176 } else if (isTrace(first
)) {
1178 String lengthName
= parseTraceScope(lengthChildren
);
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$
1184 /* Create the sequence declaration. */
1185 declaration
= new SequenceDeclaration(lengthName
,
1188 } else if (isStream(first
)) {
1190 String lengthName
= parseStreamScope(lengthChildren
);
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$
1196 /* Create the sequence declaration. */
1197 declaration
= new SequenceDeclaration(lengthName
,
1199 } else if (isEvent(first
)) {
1201 String lengthName
= parseEventScope(lengthChildren
);
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$
1207 /* Create the sequence declaration. */
1208 declaration
= new SequenceDeclaration(lengthName
,
1211 throw childTypeError(first
);
1216 if (identifier
!= null) {
1217 final String text
= identifier
.getText();
1218 identifierSB
.append(text
);
1219 registerType(declaration
, text
);
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
);
1231 } else if (declaration
instanceof VariantDeclaration
) {
1232 currentScope
.registerVariant(identifier
, (VariantDeclaration
) declaration
);
1236 private static String
parseStreamScope(List
<CommonTree
> lengthChildren
) throws ParseException
{
1237 List
<CommonTree
> sublist
= lengthChildren
.subList(1, lengthChildren
.size());
1239 CommonTree nextElem
= (CommonTree
) lengthChildren
.get(1).getChild(0);
1240 String lengthName
= null;
1241 if (isUnaryString(nextElem
)) {
1242 lengthName
= parseUnaryString(nextElem
);
1245 int type
= nextElem
.getType();
1246 if ((CTFParser
.tokenNames
[CTFParser
.EVENT
]).equals(lengthName
)) {
1247 type
= CTFParser
.EVENT
;
1250 case CTFParser
.IDENTIFIER
:
1251 lengthName
= concatenateUnaryStrings(sublist
);
1253 case CTFParser
.EVENT
:
1254 lengthName
= parseEventScope(sublist
);
1257 if (lengthName
== null) {
1258 throw new ParseException("Unsupported scope stream." + nextElem
); //$NON-NLS-1$
1261 return MetadataStrings
.STREAM
+ '.' + lengthName
;
1264 private static String
parseEventScope(List
<CommonTree
> lengthChildren
) throws ParseException
{
1265 CommonTree nextElem
= (CommonTree
) lengthChildren
.get(1).getChild(0);
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
);
1274 throw new ParseException("Unsupported scope event." + nextElem
); //$NON-NLS-1$
1279 private static String
parseTraceScope(List
<CommonTree
> lengthChildren
) throws ParseException
{
1280 CommonTree nextElem
= (CommonTree
) lengthChildren
.get(1).getChild(0);
1282 switch (nextElem
.getType()) {
1283 case CTFParser
.IDENTIFIER
:
1284 lengthName
= concatenateUnaryStrings(lengthChildren
.subList(1, lengthChildren
.size()));
1286 case CTFParser
.STREAM
:
1287 return parseStreamScope(lengthChildren
.subList(1, lengthChildren
.size()));
1289 throw new ParseException("Unsupported scope trace." + nextElem
); //$NON-NLS-1$
1294 private static boolean isEvent(CommonTree first
) {
1295 return first
.getType() == CTFParser
.EVENT
;
1298 private static boolean isStream(CommonTree first
) {
1299 return first
.getType() == CTFParser
.STREAM
;
1302 private static boolean isTrace(CommonTree first
) {
1303 return first
.getType() == CTFParser
.TRACE
;
1306 private boolean isSignedIntegerField(String lengthName
) throws ParseException
{
1307 IDeclaration decl
= getCurrentScope().lookupIdentifierRecursive(lengthName
);
1308 if (decl
instanceof IntegerDeclaration
) {
1309 return ((IntegerDeclaration
) decl
).isSigned();
1311 throw new ParseException("Is not an integer: " + lengthName
); //$NON-NLS-1$
1315 private IDeclaration
parseTypeSpecifierList(CommonTree typeSpecifierList
) throws ParseException
{
1316 return parseTypeSpecifierList(typeSpecifierList
, null, null);
1320 * Parses a type specifier list and returns the corresponding declaration.
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.
1331 private IDeclaration
parseTypeSpecifierList(CommonTree typeSpecifierList
,
1332 List
<CommonTree
> pointerList
, CommonTree identifier
) throws ParseException
{
1333 IDeclaration declaration
= null;
1336 * By looking at the first element of the type specifier list, we can
1337 * determine which type it belongs to.
1339 CommonTree firstChild
= (CommonTree
) typeSpecifierList
.getChild(0);
1341 switch (firstChild
.getType()) {
1342 case CTFParser
.FLOATING_POINT
:
1343 declaration
= parseFloat(firstChild
);
1345 case CTFParser
.INTEGER
:
1346 declaration
= parseInteger(firstChild
);
1348 case CTFParser
.STRING
:
1349 declaration
= parseString(firstChild
);
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
);
1365 case CTFParser
.VARIANT
:
1366 declaration
= parseVariant(firstChild
);
1368 case CTFParser
.ENUM
:
1369 declaration
= parseEnum(firstChild
);
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
);
1387 throw childTypeError(firstChild
);
1393 private IDeclaration
parseFloat(CommonTree floatingPoint
)
1394 throws ParseException
{
1396 List
<CommonTree
> children
= floatingPoint
.getChildren();
1399 * If the integer has no attributes, then it is missing the size
1400 * attribute which is required
1402 if (children
== null) {
1403 throw new ParseException("float: missing size attribute"); //$NON-NLS-1$
1406 /* The return value */
1407 FloatDeclaration floatDeclaration
= null;
1408 ByteOrder byteOrder
= fTrace
.getByteOrder();
1411 int exponent
= DEFAULT_FLOAT_EXPONENT
;
1412 int mantissa
= DEFAULT_FLOAT_MANTISSA
;
1414 /* Iterate on all integer children */
1415 for (CommonTree child
: children
) {
1416 switch (child
.getType()) {
1417 case CTFParser
.CTF_EXPRESSION_VAL
:
1419 * An assignment expression must have 2 children, left and right
1422 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1423 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1425 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1427 if (!isAnyUnaryString(leftStrings
.get(0))) {
1428 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1430 String left
= concatenateUnaryStrings(leftStrings
);
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
);
1441 throw new ParseException("Float: unknown attribute " + left
); //$NON-NLS-1$
1446 throw childTypeError(child
);
1449 int size
= mantissa
+ exponent
;
1451 throw new ParseException("Float missing size attribute"); //$NON-NLS-1$
1454 if (alignment
== 0) {
1455 alignment
= DEFAULT_ALIGNMENT
;
1458 floatDeclaration
= new FloatDeclaration(exponent
, mantissa
, byteOrder
, alignment
);
1460 return floatDeclaration
;
1465 * Parses a type specifier list as a user-declared type.
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).
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
);
1483 * Use the string representation to search the type in the current scope
1485 IDeclaration decl
= getCurrentScope().lookupTypeRecursive(
1486 typeStringRepresentation
);
1489 throw new ParseException("Type " + typeStringRepresentation
//$NON-NLS-1$
1490 + " has not been defined."); //$NON-NLS-1$
1497 * Parses an integer declaration node.
1501 * @return The corresponding integer declaration.
1502 * @throws ParseException
1504 private IntegerDeclaration
parseInteger(CommonTree integer
)
1505 throws ParseException
{
1507 List
<CommonTree
> children
= integer
.getChildren();
1510 * If the integer has no attributes, then it is missing the size
1511 * attribute which is required
1513 if (children
== null) {
1514 throw new ParseException("integer: missing size attribute"); //$NON-NLS-1$
1517 /* The return value */
1518 IntegerDeclaration integerDeclaration
= null;
1519 boolean signed
= false;
1520 ByteOrder byteOrder
= fTrace
.getByteOrder();
1523 int base
= DEFAULT_INT_BASE
;
1525 String clock
= EMPTY_STRING
;
1527 Encoding encoding
= Encoding
.NONE
;
1529 /* Iterate on all integer children */
1530 for (CommonTree child
: children
) {
1531 switch (child
.getType()) {
1532 case CTFParser
.CTF_EXPRESSION_VAL
:
1534 * An assignment expression must have 2 children, left and right
1537 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1538 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1540 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1542 if (!isAnyUnaryString(leftStrings
.get(0))) {
1543 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1545 String left
= concatenateUnaryStrings(leftStrings
);
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
);
1562 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownIntegerAttributeWarning
+ " " + left
); //$NON-NLS-1$
1567 throw childTypeError(child
);
1572 throw new ParseException("Invalid size attribute in Integer: " + size
); //$NON-NLS-1$
1575 if (alignment
== 0) {
1576 alignment
= DEFAULT_ALIGNMENT
;
1579 integerDeclaration
= IntegerDeclaration
.createDeclaration((int) size
, signed
, base
,
1580 byteOrder
, encoding
, clock
, alignment
);
1582 return integerDeclaration
;
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
;
1591 private static StringDeclaration
parseString(CommonTree string
)
1592 throws ParseException
{
1594 List
<CommonTree
> children
= string
.getChildren();
1595 StringDeclaration stringDeclaration
= null;
1597 if (children
== null) {
1598 stringDeclaration
= StringDeclaration
.getStringDeclaration(Encoding
.UTF8
);
1600 Encoding encoding
= Encoding
.UTF8
;
1601 for (CommonTree child
: children
) {
1602 switch (child
.getType()) {
1603 case CTFParser
.CTF_EXPRESSION_VAL
:
1605 * An assignment expression must have 2 children, left and
1609 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1610 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1612 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1614 if (!isAnyUnaryString(leftStrings
.get(0))) {
1615 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1617 String left
= concatenateUnaryStrings(leftStrings
);
1619 if (left
.equals(ENCODING
)) {
1620 encoding
= getEncoding(rightNode
);
1622 throw new ParseException("String: unknown attribute " //$NON-NLS-1$
1628 throw childTypeError(child
);
1632 stringDeclaration
= StringDeclaration
.getStringDeclaration(encoding
);
1635 return stringDeclaration
;
1639 * Parses a struct declaration and returns the corresponding declaration.
1643 * @return The corresponding struct declaration.
1644 * @throws ParseException
1646 private StructDeclaration
parseStruct(CommonTree struct
, CommonTree identifier
)
1647 throws ParseException
{
1649 List
<CommonTree
> children
= struct
.getChildren();
1651 /* The return value */
1652 StructDeclaration structDeclaration
= null;
1655 String structName
= null;
1656 boolean hasName
= false;
1659 CommonTree structBody
= null;
1660 boolean hasBody
= false;
1663 long structAlign
= 0;
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
: {
1670 CommonTree structNameIdentifier
= (CommonTree
) child
.getChild(0);
1671 structName
= structNameIdentifier
.getText();
1674 case CTFParser
.STRUCT_BODY
: {
1680 case CTFParser
.ALIGN
: {
1681 CommonTree structAlignExpression
= (CommonTree
) child
.getChild(0);
1683 structAlign
= getAlignment(structAlignExpression
);
1687 throw childTypeError(child
);
1691 if (!hasName
&& identifier
!= null) {
1692 structName
= identifier
.getText();
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.
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.
1709 * If it has both, then we create the type declaration and register it
1710 * to the current scope.
1712 * If it has none, then what are we doing here ?
1716 * If struct has a name, check if already defined in the current
1719 if (hasName
&& (getCurrentScope().lookupStruct(structName
) != null)) {
1720 throw new ParseException("struct " + structName
//$NON-NLS-1$
1721 + " already defined."); //$NON-NLS-1$
1723 /* Create the declaration */
1724 structDeclaration
= new StructDeclaration(structAlign
);
1726 /* Parse the body */
1727 parseStructBody(structBody
, structDeclaration
, structName
);
1729 /* If struct has name, add it to the current scope. */
1731 getCurrentScope().registerStruct(structName
, structDeclaration
);
1733 } else /* !hasBody */ {
1735 /* Name and !body */
1737 /* Lookup the name in the current scope. */
1738 structDeclaration
= getCurrentScope().lookupStructRecursive(structName
);
1741 * If not found, it means that a struct with such name has not
1744 if (structDeclaration
== null) {
1745 throw new ParseException("struct " + structName
//$NON-NLS-1$
1746 + " is not defined"); //$NON-NLS-1$
1749 /* !Name and !body */
1751 /* We can't do anything with that. */
1752 throw new ParseException("struct with no name and no body"); //$NON-NLS-1$
1755 return StructDeclarationFlattener
.tryFlattenStruct(structDeclaration
);
1759 * Parses a struct body, adding the fields to specified structure
1763 * A STRUCT_BODY node.
1764 * @param structDeclaration
1765 * The struct declaration.
1766 * @throws ParseException
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();
1776 * If structDeclaration is null, structBody has no children and the
1777 * struct body is empty.
1779 pushNamedScope(structName
, MetadataStrings
.STRUCT
);
1781 for (CommonTree declarationNode
: structDeclarations
) {
1782 switch (declarationNode
.getType()) {
1783 case CTFParser
.TYPEALIAS
:
1784 parseTypealias(declarationNode
);
1786 case CTFParser
.TYPEDEF
:
1787 parseTypedef(declarationNode
);
1788 parseStructDeclaration(declarationNode
, structDeclaration
);
1790 case CTFParser
.SV_DECLARATION
:
1791 parseStructDeclaration(declarationNode
, structDeclaration
);
1794 throw childTypeError(declarationNode
);
1801 * Parses a declaration found in a struct.
1803 * @param declaration
1804 * A SV_DECLARATION node.
1806 * A struct declaration. (I know, little name clash here...)
1807 * @throws ParseException
1809 private void parseStructDeclaration(CommonTree declaration
,
1810 StructDeclaration struct
) throws ParseException
{
1812 /* Get the type specifier list node */
1813 CommonTree typeSpecifierListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_SPECIFIER_LIST
);
1815 /* Get the type declarator list node */
1816 CommonTree typeDeclaratorListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_DECLARATOR_LIST
);
1818 /* Get the type declarator list */
1819 List
<CommonTree
> typeDeclaratorList
= typeDeclaratorListNode
.getChildren();
1822 * For each type declarator, parse the declaration and add a field to
1825 for (CommonTree typeDeclaratorNode
: typeDeclaratorList
) {
1827 StringBuilder identifierSB
= new StringBuilder();
1829 IDeclaration decl
= parseTypeDeclarator(typeDeclaratorNode
,
1830 typeSpecifierListNode
, identifierSB
);
1831 String fieldName
= identifierSB
.toString();
1832 getCurrentScope().registerIdentifier(fieldName
, decl
);
1834 if (struct
.hasField(fieldName
)) {
1835 throw new ParseException("struct: duplicate field " //$NON-NLS-1$
1839 struct
.addField(fieldName
, decl
);
1845 * Parses an enum declaration and returns the corresponding declaration.
1849 * @return The corresponding enum declaration.
1850 * @throws ParseException
1852 private EnumDeclaration
parseEnum(CommonTree theEnum
) throws ParseException
{
1854 List
<CommonTree
> children
= theEnum
.getChildren();
1856 /* The return value */
1857 EnumDeclaration enumDeclaration
= null;
1860 String enumName
= null;
1863 CommonTree enumBody
= null;
1865 /* Container type */
1866 IntegerDeclaration containerTypeDeclaration
= null;
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();
1876 case CTFParser
.ENUM_BODY
: {
1880 case CTFParser
.ENUM_CONTAINER_TYPE
: {
1881 containerTypeDeclaration
= parseEnumContainerType(child
);
1885 throw childTypeError(child
);
1890 * If the container type has not been defined explicitly, we assume it
1893 if (containerTypeDeclaration
== null) {
1894 IDeclaration enumDecl
;
1896 * it could be because the enum was already declared.
1898 if (enumName
!= null) {
1899 getCurrentScope().setName(enumName
);
1900 enumDecl
= getCurrentScope().lookupEnumRecursive(enumName
);
1901 if (enumDecl
!= null) {
1902 return (EnumDeclaration
) enumDecl
;
1906 IDeclaration decl
= getCurrentScope().lookupTypeRecursive("int"); //$NON-NLS-1$
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$
1914 containerTypeDeclaration
= (IntegerDeclaration
) decl
;
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.
1921 if (enumBody
!= null) {
1923 * If enum has a name, check if already defined in the current
1926 if ((enumName
!= null)
1927 && (getCurrentScope().lookupEnum(enumName
) != null)) {
1928 throw new ParseException("enum " + enumName
//$NON-NLS-1$
1929 + " already defined"); //$NON-NLS-1$
1932 /* Create the declaration */
1933 enumDeclaration
= new EnumDeclaration(containerTypeDeclaration
);
1935 /* Parse the body */
1936 parseEnumBody(enumBody
, enumDeclaration
, enumName
);
1938 /* If the enum has name, add it to the current scope. */
1939 if (enumName
!= null) {
1940 getCurrentScope().registerEnum(enumName
, enumDeclaration
);
1943 if (enumName
!= null) {
1944 /* Name and !body */
1946 /* Lookup the name in the current scope. */
1947 enumDeclaration
= getCurrentScope().lookupEnumRecursive(enumName
);
1950 * If not found, it means that an enum with such name has not
1953 if (enumDeclaration
== null) {
1954 throw new ParseException("enum " + enumName
//$NON-NLS-1$
1955 + " is not defined"); //$NON-NLS-1$
1958 /* !Name and !body */
1959 throw new ParseException("enum with no name and no body"); //$NON-NLS-1$
1963 return enumDeclaration
;
1968 * Parses an enum body, adding the enumerators to the specified enum
1972 * An ENUM_BODY node.
1973 * @param enumDeclaration
1974 * The enum declaration.
1975 * @throws ParseException
1977 private void parseEnumBody(CommonTree enumBody
,
1978 EnumDeclaration enumDeclaration
, @Nullable String enumName
) throws ParseException
{
1980 List
<CommonTree
> enumerators
= enumBody
.getChildren();
1981 /* enum body can't be empty (unlike struct). */
1983 pushNamedScope(enumName
, MetadataStrings
.ENUM
);
1986 * Start at -1, so that if the first enumrator has no explicit value, it
1991 for (CommonTree enumerator
: enumerators
) {
1992 lastHigh
= parseEnumEnumerator(enumerator
, enumDeclaration
,
2001 * Parses an enumerator node and adds an enumerator declaration to an
2002 * enumeration declaration.
2004 * The high value of the range of the last enumerator is needed in case the
2005 * current enumerator does not specify its value.
2008 * An ENUM_ENUMERATOR node.
2009 * @param enumDeclaration
2010 * en enumeration declaration to which will be added the
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
2017 private static long parseEnumEnumerator(CommonTree enumerator
,
2018 EnumDeclaration enumDeclaration
, long lastHigh
)
2019 throws ParseException
{
2021 List
<CommonTree
> children
= enumerator
.getChildren();
2023 long low
= 0, high
= 0;
2024 boolean valueSpecified
= false;
2025 String label
= null;
2027 for (CommonTree child
: children
) {
2028 if (isAnyUnaryString(child
)) {
2029 label
= parseUnaryString(child
);
2030 } else if (child
.getType() == CTFParser
.ENUM_VALUE
) {
2032 valueSpecified
= true;
2034 low
= parseUnaryInteger((CommonTree
) child
.getChild(0));
2036 } else if (child
.getType() == CTFParser
.ENUM_VALUE_RANGE
) {
2038 valueSpecified
= true;
2040 low
= parseUnaryInteger((CommonTree
) child
.getChild(0));
2041 high
= parseUnaryInteger((CommonTree
) child
.getChild(1));
2043 throw childTypeError(child
);
2047 if (!valueSpecified
) {
2053 throw new ParseException("enum low value greater than high value"); //$NON-NLS-1$
2056 if (!enumDeclaration
.add(low
, high
, label
)) {
2057 throw new ParseException("enum declarator values overlap."); //$NON-NLS-1$
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$
2069 * Parses an enum container type node and returns the corresponding integer
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
2079 private IntegerDeclaration
parseEnumContainerType(
2080 CommonTree enumContainerType
) throws ParseException
{
2082 /* Get the child, which should be a type specifier list */
2083 CommonTree typeSpecifierList
= (CommonTree
) enumContainerType
.getChild(0);
2085 /* Parse it and get the corresponding declaration */
2086 IDeclaration decl
= parseTypeSpecifierList(typeSpecifierList
);
2088 /* If is is an integer, return it, else throw an error */
2089 if (decl
instanceof IntegerDeclaration
) {
2090 return (IntegerDeclaration
) decl
;
2092 throw new ParseException("enum container type must be an integer"); //$NON-NLS-1$
2095 private VariantDeclaration
parseVariant(CommonTree variant
)
2096 throws ParseException
{
2098 List
<CommonTree
> children
= variant
.getChildren();
2099 VariantDeclaration variantDeclaration
= null;
2101 boolean hasName
= false;
2102 String variantName
= null;
2104 boolean hasBody
= false;
2105 CommonTree variantBody
= null;
2107 boolean hasTag
= false;
2108 String variantTag
= null;
2110 for (CommonTree child
: children
) {
2111 switch (child
.getType()) {
2112 case CTFParser
.VARIANT_NAME
:
2116 CommonTree variantNameIdentifier
= (CommonTree
) child
.getChild(0);
2118 variantName
= variantNameIdentifier
.getText();
2121 case CTFParser
.VARIANT_TAG
:
2125 CommonTree variantTagIdentifier
= (CommonTree
) child
.getChild(0);
2127 variantTag
= variantTagIdentifier
.getText();
2130 case CTFParser
.VARIANT_BODY
:
2134 variantBody
= child
;
2138 throw childTypeError(child
);
2144 * If variant has a name, check if already defined in the current
2148 && (getCurrentScope().lookupVariant(variantName
) != null)) {
2149 throw new ParseException("variant " + variantName
//$NON-NLS-1$
2150 + " already defined."); //$NON-NLS-1$
2153 /* Create the declaration */
2154 variantDeclaration
= new VariantDeclaration();
2156 /* Parse the body */
2157 parseVariantBody(variantBody
, variantDeclaration
, variantName
);
2159 /* If variant has name, add it to the current scope. */
2161 getCurrentScope().registerVariant(variantName
,
2162 variantDeclaration
);
2164 } else /* !hasBody */ {
2166 /* Name and !body */
2168 /* Lookup the name in the current scope. */
2169 variantDeclaration
= getCurrentScope().lookupVariantRecursive(
2173 * If not found, it means that a struct with such name has not
2176 if (variantDeclaration
== null) {
2177 throw new ParseException("variant " + variantName
//$NON-NLS-1$
2178 + " is not defined"); //$NON-NLS-1$
2181 /* !Name and !body */
2183 /* We can't do anything with that. */
2184 throw new ParseException("variant with no name and no body"); //$NON-NLS-1$
2189 variantDeclaration
.setTag(variantTag
);
2191 IDeclaration decl
= getCurrentScope().lookupIdentifierRecursive(variantTag
);
2193 throw new ParseException("Variant tag not found: " + variantTag
); //$NON-NLS-1$
2195 if (!(decl
instanceof EnumDeclaration
)) {
2196 throw new ParseException("Variant tag must be an enum: " + variantTag
); //$NON-NLS-1$
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$
2206 return variantDeclaration
;
2209 private void parseVariantBody(CommonTree variantBody
,
2210 VariantDeclaration variantDeclaration
, @Nullable String variantName
) throws ParseException
{
2212 List
<CommonTree
> variantDeclarations
= variantBody
.getChildren();
2214 pushNamedScope(variantName
, MetadataStrings
.VARIANT
);
2216 for (CommonTree declarationNode
: variantDeclarations
) {
2217 switch (declarationNode
.getType()) {
2218 case CTFParser
.TYPEALIAS
:
2219 parseTypealias(declarationNode
);
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());
2227 case CTFParser
.SV_DECLARATION
:
2228 parseVariantDeclaration(declarationNode
, variantDeclaration
);
2231 throw childTypeError(declarationNode
);
2238 private void parseVariantDeclaration(CommonTree declaration
,
2239 VariantDeclaration variant
) throws ParseException
{
2241 /* Get the type specifier list node */
2242 CommonTree typeSpecifierListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_SPECIFIER_LIST
);
2244 /* Get the type declarator list node */
2245 CommonTree typeDeclaratorListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_DECLARATOR_LIST
);
2247 /* Get the type declarator list */
2248 List
<CommonTree
> typeDeclaratorList
= typeDeclaratorListNode
.getChildren();
2251 * For each type declarator, parse the declaration and add a field to
2254 for (CommonTree typeDeclaratorNode
: typeDeclaratorList
) {
2256 StringBuilder identifierSB
= new StringBuilder();
2258 IDeclaration decl
= parseTypeDeclarator(typeDeclaratorNode
,
2259 typeSpecifierListNode
, identifierSB
);
2261 String name
= identifierSB
.toString();
2263 if (variant
.hasField(name
)) {
2264 throw new ParseException("variant: duplicate field " //$NON-NLS-1$
2268 getCurrentScope().registerIdentifier(name
, decl
);
2270 variant
.addField(name
, decl
);
2275 * Creates the string representation of a type declaration (type specifier
2278 * @param typeSpecifierList
2279 * A TYPE_SPECIFIER_LIST node.
2281 * A list of POINTER nodes.
2282 * @return The string representation.
2283 * @throws ParseException
2285 private static String
createTypeDeclarationString(
2286 CommonTree typeSpecifierList
, List
<CommonTree
> pointers
)
2287 throws ParseException
{
2288 StringBuilder sb
= new StringBuilder();
2290 createTypeSpecifierListString(typeSpecifierList
, sb
);
2291 createPointerListString(pointers
, sb
);
2293 return sb
.toString();
2297 * Creates the string representation of a list of type specifiers.
2299 * @param typeSpecifierList
2300 * A TYPE_SPECIFIER_LIST node.
2302 * A StringBuilder to which will be appended the string.
2303 * @throws ParseException
2305 private static void createTypeSpecifierListString(
2306 CommonTree typeSpecifierList
, StringBuilder sb
)
2307 throws ParseException
{
2309 List
<CommonTree
> children
= typeSpecifierList
.getChildren();
2311 boolean firstItem
= true;
2313 for (CommonTree child
: children
) {
2321 /* Append the string that represents this type specifier. */
2322 createTypeSpecifierString(child
, sb
);
2327 * Creates the string representation of a type specifier.
2329 * @param typeSpecifier
2330 * A TYPE_SPECIFIER node.
2332 * A StringBuilder to which will be appended the string.
2333 * @throws ParseException
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());
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$
2360 CommonTree structNameIdentifier
= (CommonTree
) structName
.getChild(0);
2362 sb
.append(structNameIdentifier
.getText());
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$
2371 CommonTree variantNameIdentifier
= (CommonTree
) variantName
.getChild(0);
2373 sb
.append(variantNameIdentifier
.getText());
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$
2382 CommonTree enumNameIdentifier
= (CommonTree
) enumName
.getChild(0);
2384 sb
.append(enumNameIdentifier
.getText());
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$
2392 throw childTypeError(typeSpecifier
);
2397 * Creates the string representation of a list of pointers.
2399 * @param pointerList
2400 * A list of pointer nodes. If pointerList is null, this function
2403 * A stringbuilder to which will be appended the string.
2405 private static void createPointerListString(List
<CommonTree
> pointerList
,
2407 if (pointerList
== null) {
2411 for (CommonTree pointer
: pointerList
) {
2413 sb
.append(" *"); //$NON-NLS-1$
2414 if (pointer
.getChildCount() > 0) {
2416 sb
.append(" const"); //$NON-NLS-1$
2423 * The node to check.
2424 * @return True if the given node is an unary string.
2426 private static boolean isUnaryString(CommonTree node
) {
2427 return ((node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING
));
2432 * The node to check.
2433 * @return True if the given node is any type of unary string (no quotes,
2436 private static boolean isAnyUnaryString(CommonTree node
) {
2437 return ((node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING
) || (node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING_QUOTES
));
2442 * The node to check.
2443 * @return True if the given node is an unary integer.
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
));
2451 * Parses a unary string node and return the string value.
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.
2459 * It would be really nice to remove the quotes earlier, such as in the
2462 private static String
parseUnaryString(CommonTree unaryString
) {
2464 CommonTree value
= (CommonTree
) unaryString
.getChild(0);
2465 if (value
.getType() == CTFParser
.UNARY_EXPRESSION_STRING
) {
2466 value
= (CommonTree
) value
.getChild(0);
2468 String strval
= value
.getText();
2471 if (unaryString
.getType() == CTFParser
.UNARY_EXPRESSION_STRING_QUOTES
) {
2472 strval
= strval
.substring(1, strval
.length() - 1);
2479 * Parses an unary integer (dec, hex or oct).
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)
2487 private static long parseUnaryInteger(CommonTree unaryInteger
) throws ParseException
{
2489 List
<CommonTree
> children
= unaryInteger
.getChildren();
2490 CommonTree value
= children
.get(0);
2491 String strval
= value
.getText();
2495 intval
= Long
.decode(strval
);
2496 } catch (NumberFormatException e
) {
2497 throw new ParseException("Invalid integer format: " + strval
, e
); //$NON-NLS-1$
2500 /* The rest of children are sign */
2501 if ((children
.size() % 2) == 0) {
2507 private static long getMajorOrMinor(CommonTree rightNode
)
2508 throws ParseException
{
2510 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2512 if (isUnaryInteger(firstChild
)) {
2513 if (rightNode
.getChildCount() > 1) {
2514 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2517 long m
= parseUnaryInteger(firstChild
);
2520 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2525 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2528 private static UUID
getUUID(CommonTree rightNode
) throws ParseException
{
2530 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2532 if (isAnyUnaryString(firstChild
)) {
2533 if (rightNode
.getChildCount() > 1) {
2534 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2537 String uuidstr
= parseUnaryString(firstChild
);
2540 return UUID
.fromString(uuidstr
);
2541 } catch (IllegalArgumentException e
) {
2542 throw new ParseException("Invalid format for UUID", e
); //$NON-NLS-1$
2545 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2549 * Gets the value of a "signed" integer attribute.
2553 * @return The "signed" value as a boolean.
2554 * @throws ParseException
2556 private static boolean getSigned(CommonTree rightNode
)
2557 throws ParseException
{
2559 boolean ret
= false;
2560 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2562 if (isUnaryString(firstChild
)) {
2563 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
2565 if (strval
.equals(MetadataStrings
.TRUE
)
2566 || strval
.equals(MetadataStrings
.TRUE2
)) {
2568 } else if (strval
.equals(MetadataStrings
.FALSE
)
2569 || strval
.equals(MetadataStrings
.FALSE2
)) {
2572 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2573 + firstChild
.getChild(0).getText());
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$
2581 long intval
= parseUnaryInteger(firstChild
);
2585 } else if (intval
== 0) {
2588 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2589 + firstChild
.getChild(0).getText());
2592 throw new ParseException();
2599 * Gets the value of a "byte_order" integer attribute.
2603 * @return The "byte_order" value.
2604 * @throws ParseException
2606 private ByteOrder
getByteOrder(CommonTree rightNode
) throws ParseException
{
2608 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2610 if (isUnaryString(firstChild
)) {
2611 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
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();
2621 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2624 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2628 * Determines if the given value is a valid alignment value.
2631 * The value to check.
2632 * @return True if it is valid.
2634 private static boolean isValidAlignment(long alignment
) {
2635 return !((alignment
<= 0) || ((alignment
& (alignment
- 1)) != 0));
2639 * Gets the value of a "size" integer attribute.
2643 * @return The "size" value.
2644 * @throws ParseException
2646 private static long getSize(CommonTree rightNode
) throws ParseException
{
2648 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2650 if (isUnaryInteger(firstChild
)) {
2651 if (rightNode
.getChildCount() > 1) {
2652 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2655 long size
= parseUnaryInteger(firstChild
);
2658 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2663 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2667 * Gets the value of a "align" integer or struct attribute.
2670 * A CTF_RIGHT node or directly an unary integer.
2671 * @return The align value.
2672 * @throws ParseException
2674 private static long getAlignment(CommonTree node
) throws ParseException
{
2677 * If a CTF_RIGHT node was passed, call getAlignment with the first
2680 if (node
.getType() == CTFParser
.CTF_RIGHT
) {
2681 if (node
.getChildCount() > 1) {
2682 throw new ParseException("Invalid alignment value"); //$NON-NLS-1$
2685 return getAlignment((CommonTree
) node
.getChild(0));
2686 } else if (isUnaryInteger(node
)) {
2687 long alignment
= parseUnaryInteger(node
);
2689 if (!isValidAlignment(alignment
)) {
2690 throw new ParseException("Invalid value for alignment : " //$NON-NLS-1$
2696 throw new ParseException("Invalid value for alignment"); //$NON-NLS-1$
2700 * Gets the value of a "base" integer attribute.
2703 * An CTF_RIGHT node.
2704 * @return The "base" value.
2705 * @throws ParseException
2707 private static int getBase(CommonTree rightNode
) throws ParseException
{
2709 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2711 if (isUnaryInteger(firstChild
)) {
2712 if (rightNode
.getChildCount() > 1) {
2713 throw new ParseException("invalid base value"); //$NON-NLS-1$
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
;
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
;
2744 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2747 throw new ParseException("invalid value for base"); //$NON-NLS-1$
2752 * Gets the value of an "encoding" integer attribute.
2756 * @return The "encoding" value.
2757 * @throws ParseException
2760 private static Encoding
getEncoding(CommonTree rightNode
)
2761 throws ParseException
{
2763 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2765 if (isUnaryString(firstChild
)) {
2766 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
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
;
2775 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2778 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2781 private static long getStreamID(CommonTree rightNode
) throws ParseException
{
2783 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2785 if (isUnaryInteger(firstChild
)) {
2786 if (rightNode
.getChildCount() > 1) {
2787 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2790 long intval
= parseUnaryInteger(firstChild
);
2794 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2797 private static String
getEventName(CommonTree rightNode
)
2798 throws ParseException
{
2800 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2802 if (isAnyUnaryString(firstChild
)) {
2803 String str
= concatenateUnaryStrings(rightNode
.getChildren());
2807 throw new ParseException("invalid value for event name"); //$NON-NLS-1$
2810 private static long getEventID(CommonTree rightNode
) throws ParseException
{
2812 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2814 if (isUnaryInteger(firstChild
)) {
2815 if (rightNode
.getChildCount() > 1) {
2816 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
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$
2825 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2829 * Concatenates a list of unary strings separated by arrows (->) or dots.
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.
2836 private static String
concatenateUnaryStrings(List
<CommonTree
> strings
) {
2838 StringBuilder sb
= new StringBuilder();
2840 CommonTree first
= strings
.get(0);
2841 sb
.append(parseUnaryString(first
));
2843 boolean isFirst
= true;
2845 for (CommonTree ref
: strings
) {
2851 CommonTree id
= (CommonTree
) ref
.getChild(0);
2853 if (ref
.getType() == CTFParser
.ARROW
) {
2854 sb
.append("->"); //$NON-NLS-1$
2859 sb
.append(parseUnaryString(id
));
2862 return sb
.toString();
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.
2871 * The invalid child node.
2872 * @return ParseException with details
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$
2880 return new ParseException(error
);
2883 // ------------------------------------------------------------------------
2885 // ------------------------------------------------------------------------
2888 * Adds a new declaration scope on the top of the scope stack.
2890 private void pushScope(String name
) {
2891 fScope
= new DeclarationScope(getCurrentScope(), name
);
2895 * Removes the top declaration scope from the scope stack.
2897 private void popScope() {
2898 fScope
= getCurrentScope().getParentScope();
2901 private void pushNamedScope(@Nullable String name
, String defaultName
) {
2902 pushScope(name
== null ? defaultName
: name
);
2906 * Returns the current declaration scope.
2908 * @return The current declaration scope.
2910 private DeclarationScope
getCurrentScope() {