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
.HashSet
;
22 import java
.util
.LinkedList
;
23 import java
.util
.List
;
25 import java
.util
.UUID
;
27 import org
.antlr
.runtime
.tree
.CommonTree
;
28 import org
.eclipse
.core
.runtime
.IStatus
;
29 import org
.eclipse
.jdt
.annotation
.NonNull
;
30 import org
.eclipse
.jdt
.annotation
.Nullable
;
31 import org
.eclipse
.tracecompass
.ctf
.core
.event
.CTFClock
;
32 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.Encoding
;
33 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.EnumDeclaration
;
34 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.FloatDeclaration
;
35 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IDeclaration
;
36 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IEventHeaderDeclaration
;
37 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IntegerDeclaration
;
38 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.StringDeclaration
;
39 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.StructDeclaration
;
40 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.VariantDeclaration
;
41 import org
.eclipse
.tracecompass
.ctf
.core
.trace
.CTFStream
;
42 import org
.eclipse
.tracecompass
.ctf
.core
.trace
.CTFTrace
;
43 import org
.eclipse
.tracecompass
.ctf
.parser
.CTFParser
;
44 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.Activator
;
45 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.EventDeclaration
;
46 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
.exceptions
.ParseException
;
47 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.ArrayDeclaration
;
48 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.SequenceDeclaration
;
49 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.StructDeclarationFlattener
;
50 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.composite
.EventHeaderCompactDeclaration
;
51 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.composite
.EventHeaderLargeDeclaration
;
53 import com
.google
.common
.collect
.Iterables
;
58 public class IOStructGen
{
60 // ------------------------------------------------------------------------
62 // ------------------------------------------------------------------------
64 private static final @NonNull String MAP
= "map"; //$NON-NLS-1$
65 private static final @NonNull String ENCODING
= "encoding"; //$NON-NLS-1$
66 private static final @NonNull String BASE
= "base"; //$NON-NLS-1$
67 private static final @NonNull String SIZE
= "size"; //$NON-NLS-1$
68 private static final @NonNull String SIGNED
= "signed"; //$NON-NLS-1$
69 private static final @NonNull String LINE
= "line"; //$NON-NLS-1$
70 private static final @NonNull String FILE
= "file"; //$NON-NLS-1$
71 private static final @NonNull String IP
= "ip"; //$NON-NLS-1$
72 private static final @NonNull String FUNC
= "func"; //$NON-NLS-1$
73 private static final @NonNull String NAME
= "name"; //$NON-NLS-1$
74 private static final @NonNull String EMPTY_STRING
= ""; //$NON-NLS-1$
75 private static final int INTEGER_BASE_16
= 16;
76 private static final int INTEGER_BASE_10
= 10;
77 private static final int INTEGER_BASE_8
= 8;
78 private static final int INTEGER_BASE_2
= 2;
79 private static final long DEFAULT_ALIGNMENT
= 8;
80 private static final int DEFAULT_FLOAT_EXPONENT
= 8;
81 private static final int DEFAULT_FLOAT_MANTISSA
= 24;
82 private static final int DEFAULT_INT_BASE
= 10;
86 private final CTFTrace fTrace
;
87 private CommonTree fTree
;
90 * The current declaration scope.
92 private final DeclarationScope fRoot
;
93 private DeclarationScope fScope
;
96 * Data helpers needed for streaming
99 private boolean fHasBeenParsed
= false;
101 // ------------------------------------------------------------------------
103 // ------------------------------------------------------------------------
109 * the tree (ANTLR generated) with the parsed TSDL data.
111 * the trace containing the places to put all the read metadata
113 public IOStructGen(CommonTree tree
, CTFTrace trace
) {
116 fRoot
= new DeclarationScope();
121 * Parse the tree and populate the trace defined in the constructor.
123 * @throws ParseException
124 * If there was a problem parsing the metadata
126 public void generate() throws ParseException
{
131 * Parse a partial tree and populate the trace defined in the constructor.
132 * Does not check for a "trace" block as there is only one in the trace and
135 * @throws ParseException
136 * If there was a problem parsing the metadata
138 public void generateFragment() throws ParseException
{
139 parseIncompleteRoot(fTree
);
142 // ------------------------------------------------------------------------
144 // ------------------------------------------------------------------------
147 * Sets a new tree to parse
150 * the new tree to parse
152 public void setTree(CommonTree newTree
) {
157 * Parse the root node.
161 * @throws ParseException
163 private void parseRoot(CommonTree root
) throws ParseException
{
165 List
<CommonTree
> children
= root
.getChildren();
167 CommonTree traceNode
= null;
168 boolean hasStreams
= false;
169 List
<CommonTree
> events
= new ArrayList
<>();
171 for (CommonTree child
: children
) {
172 final int type
= child
.getType();
174 case CTFParser
.DECLARATION
:
175 parseRootDeclaration(child
);
177 case CTFParser
.TRACE
:
178 if (traceNode
!= null) {
179 throw new ParseException("Only one trace block is allowed"); //$NON-NLS-1$
182 parseTrace(traceNode
);
184 case CTFParser
.STREAM
:
188 case CTFParser
.EVENT
:
191 case CTFParser
.CLOCK
:
195 parseEnvironment(child
);
197 case CTFParser
.CALLSITE
:
198 parseCallsite(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
);
249 case CTFParser
.CALLSITE
:
250 parseCallsite(child
);
253 throw childTypeError(child
);
256 parseEvents(events
, !Iterables
.isEmpty(fTrace
.getStreams()));
260 private void resetScope() {
264 private void parseCallsite(CommonTree callsite
) {
266 List
<CommonTree
> children
= callsite
.getChildren();
268 String funcName
= null;
269 long lineNumber
= -1;
271 String fileName
= null;
273 for (CommonTree child
: children
) {
275 /* this is a regex to find the leading and trailing quotes */
276 final String regex
= "^\"|\"$"; //$NON-NLS-1$
278 * this is to replace the previous quotes with nothing...
279 * effectively deleting them
281 final String nullString
= EMPTY_STRING
;
282 left
= child
.getChild(0).getChild(0).getChild(0).getText();
283 if (left
.equals(NAME
)) {
284 name
= child
.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex
, nullString
);
285 } else if (left
.equals(FUNC
)) {
286 funcName
= child
.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex
, nullString
);
287 } else if (left
.equals(IP
)) {
288 ip
= Long
.decode(child
.getChild(1).getChild(0).getChild(0).getText());
289 } else if (left
.equals(FILE
)) {
290 fileName
= child
.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex
, nullString
);
291 } else if (left
.equals(LINE
)) {
292 lineNumber
= Long
.parseLong(child
.getChild(1).getChild(0).getChild(0).getText());
295 fTrace
.addCallsite(name
, funcName
, ip
, fileName
, lineNumber
);
298 private void parseEnvironment(CommonTree environment
) {
299 List
<CommonTree
> children
= environment
.getChildren();
300 for (CommonTree child
: children
) {
303 left
= child
.getChild(0).getChild(0).getChild(0).getText();
304 right
= child
.getChild(1).getChild(0).getChild(0).getText();
305 fTrace
.addEnvironmentVar(left
, right
);
309 private void parseClock(CommonTree clock
) throws ParseException
{
310 List
<CommonTree
> children
= clock
.getChildren();
311 CTFClock ctfClock
= new CTFClock();
312 for (CommonTree child
: children
) {
313 final String key
= child
.getChild(0).getChild(0).getChild(0).getText();
314 final CommonTree value
= (CommonTree
) child
.getChild(1).getChild(0).getChild(0);
315 final int type
= value
.getType();
316 final String text
= value
.getText();
318 case CTFParser
.INTEGER
:
319 case CTFParser
.DECIMAL_LITERAL
:
321 * Not a pretty hack, this is to make sure that there is no
322 * number overflow due to 63 bit integers. The offset should
323 * only really be an issue in the year 2262. the tracer in C/ASM
324 * can write an offset in an unsigned 64 bit long. In java, the
325 * last bit, being set to 1 will be read as a negative number,
326 * but since it is too big a positive it will throw an
327 * exception. this will happen in 2^63 ns from 1970. Therefore
328 * 293 years from 1970
332 numValue
= Long
.parseLong(text
);
333 } catch (NumberFormatException e
) {
334 throw new ParseException("Number conversion issue with " + text
, e
); //$NON-NLS-1$
336 ctfClock
.addAttribute(key
, numValue
);
339 ctfClock
.addAttribute(key
, text
);
343 String nameValue
= ctfClock
.getName();
344 fTrace
.addClock(nameValue
, ctfClock
);
347 private void parseTrace(CommonTree traceNode
) throws ParseException
{
349 List
<CommonTree
> children
= traceNode
.getChildren();
350 if (children
== null) {
351 throw new ParseException("Trace block is empty"); //$NON-NLS-1$
354 pushScope(MetadataStrings
.TRACE
);
356 for (CommonTree child
: children
) {
357 switch (child
.getType()) {
358 case CTFParser
.TYPEALIAS
:
359 parseTypealias(child
);
361 case CTFParser
.TYPEDEF
:
364 case CTFParser
.CTF_EXPRESSION_TYPE
:
365 case CTFParser
.CTF_EXPRESSION_VAL
:
366 parseTraceDeclaration(child
);
369 throw childTypeError(child
);
374 * If trace byte order was not specified and not using packet based
377 if (fTrace
.getByteOrder() == null) {
378 throw new ParseException("Trace byte order not set"); //$NON-NLS-1$
384 private void parseTraceDeclaration(CommonTree traceDecl
)
385 throws ParseException
{
387 /* There should be a left and right */
389 CommonTree leftNode
= (CommonTree
) traceDecl
.getChild(0);
390 CommonTree rightNode
= (CommonTree
) traceDecl
.getChild(1);
392 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
394 if (!isAnyUnaryString(leftStrings
.get(0))) {
395 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
398 String left
= concatenateUnaryStrings(leftStrings
);
400 if (left
.equals(MetadataStrings
.MAJOR
)) {
401 if (fTrace
.majorIsSet()) {
402 throw new ParseException("major is already set"); //$NON-NLS-1$
405 fTrace
.setMajor(getMajorOrMinor(rightNode
));
406 } else if (left
.equals(MetadataStrings
.MINOR
)) {
407 if (fTrace
.minorIsSet()) {
408 throw new ParseException("minor is already set"); //$NON-NLS-1$
411 fTrace
.setMinor(getMajorOrMinor(rightNode
));
412 } else if (left
.equals(MetadataStrings
.UUID_STRING
)) {
413 UUID uuid
= getUUID(rightNode
);
416 * If uuid was already set by a metadata packet, compare it to see
419 if (fTrace
.uuidIsSet()) {
420 if (fTrace
.getUUID().compareTo(uuid
) != 0) {
421 throw new ParseException("UUID mismatch. Packet says " //$NON-NLS-1$
422 + fTrace
.getUUID() + " but metadata says " + uuid
); //$NON-NLS-1$
425 fTrace
.setUUID(uuid
);
428 } else if (left
.equals(MetadataStrings
.BYTE_ORDER
)) {
429 ByteOrder byteOrder
= getByteOrder(rightNode
);
432 * If byte order was already set by a metadata packet, compare it to
435 if (fTrace
.getByteOrder() != null) {
436 if (fTrace
.getByteOrder() != byteOrder
) {
437 throw new ParseException(
438 "Endianness mismatch. Magic number says " //$NON-NLS-1$
439 + fTrace
.getByteOrder()
440 + " but metadata says " + byteOrder
); //$NON-NLS-1$
443 fTrace
.setByteOrder(byteOrder
);
444 final DeclarationScope parentScope
= fScope
.getParentScope();
446 for (String type
: parentScope
.getTypeNames()) {
447 IDeclaration d
= parentScope
.lookupType(type
);
448 if (d
instanceof IntegerDeclaration
) {
449 addByteOrder(byteOrder
, parentScope
, type
, (IntegerDeclaration
) d
);
450 } else if (d
instanceof StructDeclaration
) {
451 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
455 } else if (left
.equals(MetadataStrings
.PACKET_HEADER
)) {
456 if (fTrace
.packetHeaderIsSet()) {
457 throw new ParseException("packet.header already defined"); //$NON-NLS-1$
460 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
462 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
463 throw new ParseException("packet.header expects a type specifier"); //$NON-NLS-1$
466 IDeclaration packetHeaderDecl
= parseTypeSpecifierList(
467 typeSpecifier
, null);
469 if (!(packetHeaderDecl
instanceof StructDeclaration
)) {
470 throw new ParseException("packet.header expects a struct"); //$NON-NLS-1$
473 fTrace
.setPacketHeader((StructDeclaration
) packetHeaderDecl
);
475 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownTraceAttributeWarning
+ " " + left
); //$NON-NLS-1$
479 private static void addByteOrder(ByteOrder byteOrder
,
480 final DeclarationScope parentScope
, String name
,
481 IntegerDeclaration decl
) throws ParseException
{
483 if (decl
.getByteOrder() != byteOrder
) {
484 IntegerDeclaration newI
;
485 newI
= IntegerDeclaration
.createDeclaration(decl
.getLength(), decl
.isSigned(),
486 decl
.getBase(), byteOrder
, decl
.getEncoding(),
487 decl
.getClock(), decl
.getAlignment());
488 parentScope
.replaceType(name
, newI
);
492 private void setAlign(DeclarationScope parentScope
, StructDeclaration sd
,
493 ByteOrder byteOrder
) throws ParseException
{
495 for (String s
: sd
.getFieldsList()) {
496 IDeclaration d
= sd
.getField(s
);
498 if (d
instanceof StructDeclaration
) {
499 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
501 } else if (d
instanceof VariantDeclaration
) {
502 setAlign(parentScope
, (VariantDeclaration
) d
, byteOrder
);
503 } else if (d
instanceof IntegerDeclaration
) {
504 IntegerDeclaration decl
= (IntegerDeclaration
) d
;
505 if (decl
.getByteOrder() != byteOrder
) {
506 IntegerDeclaration newI
;
507 newI
= IntegerDeclaration
.createDeclaration(decl
.getLength(),
508 decl
.isSigned(), decl
.getBase(), byteOrder
,
509 decl
.getEncoding(), decl
.getClock(),
510 decl
.getAlignment());
511 sd
.getFields().put(s
, newI
);
517 private void setAlign(DeclarationScope parentScope
, VariantDeclaration vd
,
518 ByteOrder byteOrder
) throws ParseException
{
520 for (String s
: vd
.getFields().keySet()) {
521 IDeclaration d
= vd
.getFields().get(s
);
523 if (d
instanceof StructDeclaration
) {
524 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
526 } else if (d
instanceof IntegerDeclaration
) {
527 IntegerDeclaration decl
= (IntegerDeclaration
) d
;
528 IntegerDeclaration newI
;
529 newI
= IntegerDeclaration
.createDeclaration(decl
.getLength(),
530 decl
.isSigned(), decl
.getBase(), byteOrder
,
531 decl
.getEncoding(), decl
.getClock(),
532 decl
.getAlignment());
533 vd
.getFields().put(s
, newI
);
538 private void parseStream(CommonTree streamNode
) throws ParseException
{
540 CTFStream stream
= new CTFStream(fTrace
);
542 List
<CommonTree
> children
= streamNode
.getChildren();
543 if (children
== null) {
544 throw new ParseException("Empty stream block"); //$NON-NLS-1$
547 pushScope(MetadataStrings
.STREAM
);
549 for (CommonTree child
: children
) {
550 switch (child
.getType()) {
551 case CTFParser
.TYPEALIAS
:
552 parseTypealias(child
);
554 case CTFParser
.TYPEDEF
:
557 case CTFParser
.CTF_EXPRESSION_TYPE
:
558 case CTFParser
.CTF_EXPRESSION_VAL
:
559 parseStreamDeclaration(child
, stream
);
562 throw childTypeError(child
);
566 if (stream
.isIdSet() &&
567 (!fTrace
.packetHeaderIsSet() || !fTrace
.getPacketHeader().hasField(MetadataStrings
.STREAM_ID
))) {
568 throw new ParseException("Stream has an ID, but there is no stream_id field in packet header."); //$NON-NLS-1$
571 fTrace
.addStream(stream
);
576 private void parseStreamDeclaration(CommonTree streamDecl
, CTFStream stream
)
577 throws ParseException
{
579 /* There should be a left and right */
581 CommonTree leftNode
= (CommonTree
) streamDecl
.getChild(0);
582 CommonTree rightNode
= (CommonTree
) streamDecl
.getChild(1);
584 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
586 if (!isAnyUnaryString(leftStrings
.get(0))) {
587 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
590 String left
= concatenateUnaryStrings(leftStrings
);
592 if (left
.equals(MetadataStrings
.ID
)) {
593 if (stream
.isIdSet()) {
594 throw new ParseException("stream id already defined"); //$NON-NLS-1$
597 long streamID
= getStreamID(rightNode
);
599 stream
.setId(streamID
);
600 } else if (left
.equals(MetadataStrings
.EVENT_HEADER
)) {
601 if (stream
.isEventHeaderSet()) {
602 throw new ParseException("event.header already defined"); //$NON-NLS-1$
605 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
607 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
608 throw new ParseException("event.header expects a type specifier"); //$NON-NLS-1$
611 IDeclaration eventHeaderDecl
= parseTypeSpecifierList(
612 typeSpecifier
, null);
614 if (eventHeaderDecl
instanceof StructDeclaration
) {
615 stream
.setEventHeader((StructDeclaration
) eventHeaderDecl
);
616 } else if (eventHeaderDecl
instanceof IEventHeaderDeclaration
) {
617 stream
.setEventHeader((IEventHeaderDeclaration
) eventHeaderDecl
);
619 throw new ParseException("event.header expects a struct"); //$NON-NLS-1$
622 } else if (left
.equals(MetadataStrings
.EVENT_CONTEXT
)) {
623 if (stream
.isEventContextSet()) {
624 throw new ParseException("event.context already defined"); //$NON-NLS-1$
627 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
629 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
630 throw new ParseException("event.context expects a type specifier"); //$NON-NLS-1$
633 IDeclaration eventContextDecl
= parseTypeSpecifierList(
634 typeSpecifier
, null);
636 if (!(eventContextDecl
instanceof StructDeclaration
)) {
637 throw new ParseException("event.context expects a struct"); //$NON-NLS-1$
640 stream
.setEventContext((StructDeclaration
) eventContextDecl
);
641 } else if (left
.equals(MetadataStrings
.PACKET_CONTEXT
)) {
642 if (stream
.isPacketContextSet()) {
643 throw new ParseException("packet.context already defined"); //$NON-NLS-1$
646 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
648 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
649 throw new ParseException("packet.context expects a type specifier"); //$NON-NLS-1$
652 IDeclaration packetContextDecl
= parseTypeSpecifierList(
653 typeSpecifier
, null);
655 if (!(packetContextDecl
instanceof StructDeclaration
)) {
656 throw new ParseException("packet.context expects a struct"); //$NON-NLS-1$
659 stream
.setPacketContext((StructDeclaration
) packetContextDecl
);
661 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownStreamAttributeWarning
+ " " + left
); //$NON-NLS-1$
665 private void parseEvent(CommonTree eventNode
) throws ParseException
{
667 List
<CommonTree
> children
= eventNode
.getChildren();
668 if (children
== null) {
669 throw new ParseException("Empty event block"); //$NON-NLS-1$
672 EventDeclaration event
= new EventDeclaration();
674 pushScope(MetadataStrings
.EVENT
);
676 for (CommonTree child
: children
) {
677 switch (child
.getType()) {
678 case CTFParser
.TYPEALIAS
:
679 parseTypealias(child
);
681 case CTFParser
.TYPEDEF
:
684 case CTFParser
.CTF_EXPRESSION_TYPE
:
685 case CTFParser
.CTF_EXPRESSION_VAL
:
686 parseEventDeclaration(child
, event
);
689 throw childTypeError(child
);
693 if (!event
.nameIsSet()) {
694 throw new ParseException("Event name not set"); //$NON-NLS-1$
698 * If the event did not specify a stream, then the trace must be single
701 if (!event
.streamIsSet()) {
702 if (fTrace
.nbStreams() > 1) {
703 throw new ParseException("Event without stream_id with more than one stream"); //$NON-NLS-1$
707 * If the event did not specify a stream, the only existing stream
708 * must not have an id. Note: That behavior could be changed, it
709 * could be possible to just get the only existing stream, whatever
712 CTFStream stream
= fTrace
.getStream(null);
714 if (stream
!= null) {
715 event
.setStream(stream
);
717 throw new ParseException("Event without stream_id, but there is no stream without id"); //$NON-NLS-1$
722 * Add the event to the stream.
724 event
.getStream().addEvent(event
);
729 private void parseEventDeclaration(CommonTree eventDecl
,
730 EventDeclaration event
) throws ParseException
{
732 /* There should be a left and right */
734 CommonTree leftNode
= (CommonTree
) eventDecl
.getChild(0);
735 CommonTree rightNode
= (CommonTree
) eventDecl
.getChild(1);
737 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
739 if (!isAnyUnaryString(leftStrings
.get(0))) {
740 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
743 String left
= concatenateUnaryStrings(leftStrings
);
745 if (left
.equals(MetadataStrings
.NAME2
)) {
746 if (event
.nameIsSet()) {
747 throw new ParseException("name already defined"); //$NON-NLS-1$
750 String name
= getEventName(rightNode
);
753 } else if (left
.equals(MetadataStrings
.ID
)) {
754 if (event
.idIsSet()) {
755 throw new ParseException("id already defined"); //$NON-NLS-1$
758 long id
= getEventID(rightNode
);
759 if (id
> Integer
.MAX_VALUE
) {
760 throw new ParseException("id is greater than int.maxvalue, unsupported. id : " + id
); //$NON-NLS-1$
763 throw new ParseException("negative id, unsupported. id : " + id
); //$NON-NLS-1$
765 event
.setId((int) id
);
766 } else if (left
.equals(MetadataStrings
.STREAM_ID
)) {
767 if (event
.streamIsSet()) {
768 throw new ParseException("stream id already defined"); //$NON-NLS-1$
771 long streamId
= getStreamID(rightNode
);
773 CTFStream stream
= fTrace
.getStream(streamId
);
775 if (stream
== null) {
776 throw new ParseException("Stream " + streamId
+ " not found"); //$NON-NLS-1$ //$NON-NLS-2$
779 event
.setStream(stream
);
780 } else if (left
.equals(MetadataStrings
.CONTEXT
)) {
781 if (event
.contextIsSet()) {
782 throw new ParseException("context already defined"); //$NON-NLS-1$
785 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
787 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
788 throw new ParseException("context expects a type specifier"); //$NON-NLS-1$
791 IDeclaration contextDecl
= parseTypeSpecifierList(typeSpecifier
,
794 if (!(contextDecl
instanceof StructDeclaration
)) {
795 throw new ParseException("context expects a struct"); //$NON-NLS-1$
798 event
.setContext((StructDeclaration
) contextDecl
);
799 } else if (left
.equals(MetadataStrings
.FIELDS_STRING
)) {
800 if (event
.fieldsIsSet()) {
801 throw new ParseException("fields already defined"); //$NON-NLS-1$
804 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
806 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
807 throw new ParseException("fields expects a type specifier"); //$NON-NLS-1$
810 IDeclaration fieldsDecl
;
811 fieldsDecl
= parseTypeSpecifierList(typeSpecifier
, null);
813 if (!(fieldsDecl
instanceof StructDeclaration
)) {
814 throw new ParseException("fields expects a struct"); //$NON-NLS-1$
817 * The underscores in the event names. These underscores were added
818 * by the LTTng tracer.
820 final StructDeclaration fields
= (StructDeclaration
) fieldsDecl
;
821 event
.setFields(fields
);
822 } else if (left
.equals(MetadataStrings
.LOGLEVEL2
)) {
823 long logLevel
= parseUnaryInteger((CommonTree
) rightNode
.getChild(0));
824 event
.setLogLevel(logLevel
);
826 /* Custom event attribute, we'll add it to the attributes map */
827 String right
= parseUnaryString((CommonTree
) rightNode
.getChild(0));
828 event
.setCustomAttribute(left
, right
);
833 * Parses a declaration at the root level.
836 * The declaration subtree.
837 * @throws ParseException
839 private void parseRootDeclaration(CommonTree declaration
)
840 throws ParseException
{
842 List
<CommonTree
> children
= declaration
.getChildren();
844 for (CommonTree child
: children
) {
845 switch (child
.getType()) {
846 case CTFParser
.TYPEDEF
:
849 case CTFParser
.TYPEALIAS
:
850 parseTypealias(child
);
852 case CTFParser
.TYPE_SPECIFIER_LIST
:
853 parseTypeSpecifierList(child
, null);
856 throw childTypeError(child
);
862 * Parses a typealias node. It parses the target, the alias, and registers
863 * the type in the current scope.
867 * @throws ParseException
869 private void parseTypealias(CommonTree typealias
) throws ParseException
{
871 List
<CommonTree
> children
= typealias
.getChildren();
873 CommonTree target
= null;
874 CommonTree alias
= null;
876 for (CommonTree child
: children
) {
877 switch (child
.getType()) {
878 case CTFParser
.TYPEALIAS_TARGET
:
881 case CTFParser
.TYPEALIAS_ALIAS
:
885 throw childTypeError(child
);
889 IDeclaration targetDeclaration
= parseTypealiasTarget(target
);
891 if ((targetDeclaration
instanceof VariantDeclaration
)
892 && ((VariantDeclaration
) targetDeclaration
).isTagged()) {
893 throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
896 String aliasString
= parseTypealiasAlias(alias
);
898 getCurrentScope().registerType(aliasString
, targetDeclaration
);
902 * Parses the target part of a typealias and gets the corresponding
906 * A TYPEALIAS_TARGET node.
907 * @return The corresponding declaration.
908 * @throws ParseException
910 private IDeclaration
parseTypealiasTarget(CommonTree target
)
911 throws ParseException
{
913 List
<CommonTree
> children
= target
.getChildren();
915 CommonTree typeSpecifierList
= null;
916 CommonTree typeDeclaratorList
= null;
917 CommonTree typeDeclarator
= null;
918 StringBuilder identifierSB
= new StringBuilder();
920 for (CommonTree child
: children
) {
921 switch (child
.getType()) {
922 case CTFParser
.TYPE_SPECIFIER_LIST
:
923 typeSpecifierList
= child
;
925 case CTFParser
.TYPE_DECLARATOR_LIST
:
926 typeDeclaratorList
= child
;
929 throw childTypeError(child
);
933 if (typeDeclaratorList
!= null) {
935 * Only allow one declarator
937 * eg: "typealias uint8_t *, ** := puint8_t;" is not permitted,
938 * otherwise the new type puint8_t would maps to two different
941 if (typeDeclaratorList
.getChildCount() != 1) {
942 throw new ParseException("Only one type declarator is allowed in the typealias target"); //$NON-NLS-1$
945 typeDeclarator
= (CommonTree
) typeDeclaratorList
.getChild(0);
948 /* Parse the target type and get the declaration */
949 IDeclaration targetDeclaration
= parseTypeDeclarator(typeDeclarator
,
950 typeSpecifierList
, identifierSB
);
953 * We don't allow identifier in the target
955 * eg: "typealias uint8_t* hello := puint8_t;", the "hello" is not
958 if (identifierSB
.length() > 0) {
959 throw new ParseException("Identifier (" + identifierSB
.toString() //$NON-NLS-1$
960 + ") not expected in the typealias target"); //$NON-NLS-1$
963 return targetDeclaration
;
967 * Parses the alias part of a typealias. It parses the underlying specifier
968 * list and declarator and creates the string representation that will be
969 * used to register the type.
972 * A TYPEALIAS_ALIAS node.
973 * @return The string representation of the alias.
974 * @throws ParseException
976 private static String
parseTypealiasAlias(CommonTree alias
)
977 throws ParseException
{
979 List
<CommonTree
> children
= alias
.getChildren();
981 CommonTree typeSpecifierList
= null;
982 CommonTree typeDeclaratorList
= null;
983 CommonTree typeDeclarator
= null;
984 List
<CommonTree
> pointers
= new LinkedList
<>();
986 for (CommonTree child
: children
) {
987 switch (child
.getType()) {
988 case CTFParser
.TYPE_SPECIFIER_LIST
:
989 typeSpecifierList
= child
;
991 case CTFParser
.TYPE_DECLARATOR_LIST
:
992 typeDeclaratorList
= child
;
995 throw childTypeError(child
);
999 /* If there is a type declarator list, extract the pointers */
1000 if (typeDeclaratorList
!= null) {
1002 * Only allow one declarator
1004 * eg: "typealias uint8_t := puint8_t *, **;" is not permitted.
1006 if (typeDeclaratorList
.getChildCount() != 1) {
1007 throw new ParseException("Only one type declarator is allowed in the typealias alias"); //$NON-NLS-1$
1010 typeDeclarator
= (CommonTree
) typeDeclaratorList
.getChild(0);
1012 List
<CommonTree
> typeDeclaratorChildren
= typeDeclarator
.getChildren();
1014 for (CommonTree child
: typeDeclaratorChildren
) {
1015 switch (child
.getType()) {
1016 case CTFParser
.POINTER
:
1017 pointers
.add(child
);
1019 case CTFParser
.IDENTIFIER
:
1020 throw new ParseException("Identifier (" + child
.getText() //$NON-NLS-1$
1021 + ") not expected in the typealias target"); //$NON-NLS-1$
1023 throw childTypeError(child
);
1028 return createTypeDeclarationString(typeSpecifierList
, pointers
);
1032 * Parses a typedef node. This creates and registers a new declaration for
1033 * each declarator found in the typedef.
1037 * @throws ParseException
1038 * If there is an error creating the declaration.
1040 private void parseTypedef(CommonTree typedef
) throws ParseException
{
1042 CommonTree typeDeclaratorListNode
= (CommonTree
) typedef
.getFirstChildWithType(CTFParser
.TYPE_DECLARATOR_LIST
);
1044 CommonTree typeSpecifierListNode
= (CommonTree
) typedef
.getFirstChildWithType(CTFParser
.TYPE_SPECIFIER_LIST
);
1046 List
<CommonTree
> typeDeclaratorList
= typeDeclaratorListNode
.getChildren();
1048 for (CommonTree typeDeclaratorNode
: typeDeclaratorList
) {
1049 StringBuilder identifierSB
= new StringBuilder();
1051 IDeclaration typeDeclaration
= parseTypeDeclarator(
1052 typeDeclaratorNode
, typeSpecifierListNode
, identifierSB
);
1054 if ((typeDeclaration
instanceof VariantDeclaration
)
1055 && ((VariantDeclaration
) typeDeclaration
).isTagged()) {
1056 throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
1059 getCurrentScope().registerType(identifierSB
.toString(),
1065 * Parses a pair type declarator / type specifier list and returns the
1066 * corresponding declaration. If it is present, it also writes the
1067 * identifier of the declarator in the given {@link StringBuilder}.
1069 * @param typeDeclarator
1070 * A TYPE_DECLARATOR node.
1071 * @param typeSpecifierList
1072 * A TYPE_SPECIFIER_LIST node.
1073 * @param identifierSB
1074 * A StringBuilder that will receive the identifier found in the
1076 * @return The corresponding declaration.
1077 * @throws ParseException
1078 * If there is an error finding or creating the declaration.
1080 private IDeclaration
parseTypeDeclarator(CommonTree typeDeclarator
,
1081 CommonTree typeSpecifierList
, StringBuilder identifierSB
)
1082 throws ParseException
{
1084 IDeclaration declaration
= null;
1085 List
<CommonTree
> children
= null;
1086 List
<CommonTree
> pointers
= new LinkedList
<>();
1087 List
<CommonTree
> lengths
= new LinkedList
<>();
1088 CommonTree identifier
= null;
1090 /* Separate the tokens by type */
1091 if (typeDeclarator
!= null) {
1092 children
= typeDeclarator
.getChildren();
1093 for (CommonTree child
: children
) {
1095 switch (child
.getType()) {
1096 case CTFParser
.POINTER
:
1097 pointers
.add(child
);
1099 case CTFParser
.IDENTIFIER
:
1102 case CTFParser
.LENGTH
:
1106 throw childTypeError(child
);
1113 * Parse the type specifier list, which is the "base" type. For example,
1114 * it would be int in int a[3][len].
1116 declaration
= parseTypeSpecifierList(typeSpecifierList
, pointers
);
1119 * Each length subscript means that we must create a nested array or
1120 * sequence. For example, int a[3][len] means that we have an array of 3
1121 * (sequences of length 'len' of (int)).
1123 if (!lengths
.isEmpty()) {
1124 /* We begin at the end */
1125 Collections
.reverse(lengths
);
1127 for (CommonTree length
: lengths
) {
1129 * By looking at the first expression, we can determine whether
1130 * it is an array or a sequence.
1132 List
<CommonTree
> lengthChildren
= length
.getChildren();
1134 CommonTree first
= lengthChildren
.get(0);
1135 if (isUnaryInteger(first
)) {
1137 int arrayLength
= (int) parseUnaryInteger(first
);
1139 if (arrayLength
< 1) {
1140 throw new ParseException("Array length is negative"); //$NON-NLS-1$
1143 /* Create the array declaration. */
1144 declaration
= new ArrayDeclaration(arrayLength
, declaration
);
1145 } else if (isAnyUnaryString(first
)) {
1147 String lengthName
= concatenateUnaryStrings(lengthChildren
);
1149 /* check that lengthName was declared */
1150 if (isSignedIntegerField(lengthName
)) {
1151 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
1153 /* Create the sequence declaration. */
1154 declaration
= new SequenceDeclaration(lengthName
,
1157 throw childTypeError(first
);
1162 if (identifier
!= null) {
1163 identifierSB
.append(identifier
.getText());
1169 private boolean isSignedIntegerField(String lengthName
) throws ParseException
{
1170 IDeclaration decl
= getCurrentScope().lookupIdentifierRecursive(lengthName
);
1171 if (decl
instanceof IntegerDeclaration
) {
1172 return ((IntegerDeclaration
) decl
).isSigned();
1174 throw new ParseException("Is not an integer: " + lengthName
); //$NON-NLS-1$
1179 * Parses a type specifier list and returns the corresponding declaration.
1181 * @param typeSpecifierList
1182 * A TYPE_SPECIFIER_LIST node.
1183 * @param pointerList
1184 * A list of POINTER nodes that apply to the specified type.
1185 * @return The corresponding declaration.
1186 * @throws ParseException
1187 * If the type has not been defined or if there is an error
1188 * creating the declaration.
1190 private IDeclaration
parseTypeSpecifierList(CommonTree typeSpecifierList
,
1191 List
<CommonTree
> pointerList
) throws ParseException
{
1192 IDeclaration declaration
= null;
1195 * By looking at the first element of the type specifier list, we can
1196 * determine which type it belongs to.
1198 CommonTree firstChild
= (CommonTree
) typeSpecifierList
.getChild(0);
1200 switch (firstChild
.getType()) {
1201 case CTFParser
.FLOATING_POINT
:
1202 declaration
= parseFloat(firstChild
);
1204 case CTFParser
.INTEGER
:
1205 declaration
= parseInteger(firstChild
);
1207 case CTFParser
.STRING
:
1208 declaration
= parseString(firstChild
);
1210 case CTFParser
.STRUCT
:
1211 declaration
= parseStruct(firstChild
);
1212 StructDeclaration structDeclaration
= (StructDeclaration
) declaration
;
1213 IDeclaration idEnumDecl
= structDeclaration
.getFields().get("id"); //$NON-NLS-1$
1214 if (idEnumDecl
instanceof EnumDeclaration
) {
1215 EnumDeclaration enumDeclaration
= (EnumDeclaration
) idEnumDecl
;
1216 ByteOrder bo
= enumDeclaration
.getContainerType().getByteOrder();
1217 if (EventHeaderCompactDeclaration
.getEventHeader(bo
).isCompactEventHeader(structDeclaration
)) {
1218 declaration
= EventHeaderCompactDeclaration
.getEventHeader(bo
);
1219 } else if (EventHeaderLargeDeclaration
.getEventHeader(bo
).isLargeEventHeader(structDeclaration
)) {
1220 declaration
= EventHeaderLargeDeclaration
.getEventHeader(bo
);
1224 case CTFParser
.VARIANT
:
1225 declaration
= parseVariant(firstChild
);
1227 case CTFParser
.ENUM
:
1228 declaration
= parseEnum(firstChild
);
1230 case CTFParser
.IDENTIFIER
:
1231 case CTFParser
.FLOATTOK
:
1232 case CTFParser
.INTTOK
:
1233 case CTFParser
.LONGTOK
:
1234 case CTFParser
.SHORTTOK
:
1235 case CTFParser
.SIGNEDTOK
:
1236 case CTFParser
.UNSIGNEDTOK
:
1237 case CTFParser
.CHARTOK
:
1238 case CTFParser
.DOUBLETOK
:
1239 case CTFParser
.VOIDTOK
:
1240 case CTFParser
.BOOLTOK
:
1241 case CTFParser
.COMPLEXTOK
:
1242 case CTFParser
.IMAGINARYTOK
:
1243 declaration
= parseTypeDeclaration(typeSpecifierList
, pointerList
);
1246 throw childTypeError(firstChild
);
1252 private IDeclaration
parseFloat(CommonTree floatingPoint
)
1253 throws ParseException
{
1255 List
<CommonTree
> children
= floatingPoint
.getChildren();
1258 * If the integer has no attributes, then it is missing the size
1259 * attribute which is required
1261 if (children
== null) {
1262 throw new ParseException("float: missing size attribute"); //$NON-NLS-1$
1265 /* The return value */
1266 FloatDeclaration floatDeclaration
= null;
1267 ByteOrder byteOrder
= fTrace
.getByteOrder();
1270 int exponent
= DEFAULT_FLOAT_EXPONENT
;
1271 int mantissa
= DEFAULT_FLOAT_MANTISSA
;
1273 /* Iterate on all integer children */
1274 for (CommonTree child
: children
) {
1275 switch (child
.getType()) {
1276 case CTFParser
.CTF_EXPRESSION_VAL
:
1278 * An assignment expression must have 2 children, left and right
1281 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1282 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1284 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1286 if (!isAnyUnaryString(leftStrings
.get(0))) {
1287 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1289 String left
= concatenateUnaryStrings(leftStrings
);
1291 if (left
.equals(MetadataStrings
.EXP_DIG
)) {
1292 exponent
= (int) parseUnaryInteger((CommonTree
) rightNode
.getChild(0));
1293 } else if (left
.equals(MetadataStrings
.BYTE_ORDER
)) {
1294 byteOrder
= getByteOrder(rightNode
);
1295 } else if (left
.equals(MetadataStrings
.MANT_DIG
)) {
1296 mantissa
= (int) parseUnaryInteger((CommonTree
) rightNode
.getChild(0));
1297 } else if (left
.equals(MetadataStrings
.ALIGN
)) {
1298 alignment
= getAlignment(rightNode
);
1300 throw new ParseException("Float: unknown attribute " + left
); //$NON-NLS-1$
1305 throw childTypeError(child
);
1308 int size
= mantissa
+ exponent
;
1310 throw new ParseException("Float missing size attribute"); //$NON-NLS-1$
1313 if (alignment
== 0) {
1314 alignment
= ((size
% DEFAULT_ALIGNMENT
) == 0) ?
1 : DEFAULT_ALIGNMENT
;
1317 floatDeclaration
= new FloatDeclaration(exponent
, mantissa
, byteOrder
, alignment
);
1319 return floatDeclaration
;
1324 * Parses a type specifier list as a user-declared type.
1326 * @param typeSpecifierList
1327 * A TYPE_SPECIFIER_LIST node containing a user-declared type.
1328 * @param pointerList
1329 * A list of POINTER nodes that apply to the type specified in
1330 * typeSpecifierList.
1331 * @return The corresponding declaration.
1332 * @throws ParseException
1333 * If the type does not exist (has not been found).
1335 private IDeclaration
parseTypeDeclaration(CommonTree typeSpecifierList
,
1336 List
<CommonTree
> pointerList
) throws ParseException
{
1337 /* Create the string representation of the type declaration */
1338 String typeStringRepresentation
= createTypeDeclarationString(
1339 typeSpecifierList
, pointerList
);
1342 * Use the string representation to search the type in the current scope
1344 IDeclaration decl
= getCurrentScope().lookupTypeRecursive(
1345 typeStringRepresentation
);
1348 throw new ParseException("Type " + typeStringRepresentation
//$NON-NLS-1$
1349 + " has not been defined."); //$NON-NLS-1$
1356 * Parses an integer declaration node.
1360 * @return The corresponding integer declaration.
1361 * @throws ParseException
1363 private IntegerDeclaration
parseInteger(CommonTree integer
)
1364 throws ParseException
{
1366 List
<CommonTree
> children
= integer
.getChildren();
1369 * If the integer has no attributes, then it is missing the size
1370 * attribute which is required
1372 if (children
== null) {
1373 throw new ParseException("integer: missing size attribute"); //$NON-NLS-1$
1376 /* The return value */
1377 IntegerDeclaration integerDeclaration
= null;
1378 boolean signed
= false;
1379 ByteOrder byteOrder
= fTrace
.getByteOrder();
1382 int base
= DEFAULT_INT_BASE
;
1384 String clock
= EMPTY_STRING
;
1386 Encoding encoding
= Encoding
.NONE
;
1388 /* Iterate on all integer children */
1389 for (CommonTree child
: children
) {
1390 switch (child
.getType()) {
1391 case CTFParser
.CTF_EXPRESSION_VAL
:
1393 * An assignment expression must have 2 children, left and right
1396 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1397 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1399 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1401 if (!isAnyUnaryString(leftStrings
.get(0))) {
1402 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1404 String left
= concatenateUnaryStrings(leftStrings
);
1406 if (left
.equals(SIGNED
)) {
1407 signed
= getSigned(rightNode
);
1408 } else if (left
.equals(MetadataStrings
.BYTE_ORDER
)) {
1409 byteOrder
= getByteOrder(rightNode
);
1410 } else if (left
.equals(SIZE
)) {
1411 size
= getSize(rightNode
);
1412 } else if (left
.equals(MetadataStrings
.ALIGN
)) {
1413 alignment
= getAlignment(rightNode
);
1414 } else if (left
.equals(BASE
)) {
1415 base
= getBase(rightNode
);
1416 } else if (left
.equals(ENCODING
)) {
1417 encoding
= getEncoding(rightNode
);
1418 } else if (left
.equals(MAP
)) {
1419 clock
= getClock(rightNode
);
1421 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownIntegerAttributeWarning
+ " " + left
); //$NON-NLS-1$
1426 throw childTypeError(child
);
1431 throw new ParseException("Invalid size attribute in Integer: " + size
); //$NON-NLS-1$
1434 if (alignment
== 0) {
1435 alignment
= ((size
% DEFAULT_ALIGNMENT
) == 0) ?
1 : DEFAULT_ALIGNMENT
;
1438 integerDeclaration
= IntegerDeclaration
.createDeclaration((int) size
, signed
, base
,
1439 byteOrder
, encoding
, clock
, alignment
);
1441 return integerDeclaration
;
1445 private static String
getClock(CommonTree rightNode
) {
1446 String clock
= rightNode
.getChild(1).getChild(0).getChild(0).getText();
1447 return clock
== null ? EMPTY_STRING
: clock
;
1450 private static StringDeclaration
parseString(CommonTree string
)
1451 throws ParseException
{
1453 List
<CommonTree
> children
= string
.getChildren();
1454 StringDeclaration stringDeclaration
= null;
1456 if (children
== null) {
1457 stringDeclaration
= StringDeclaration
.getStringDeclaration(Encoding
.UTF8
);
1459 Encoding encoding
= Encoding
.UTF8
;
1460 for (CommonTree child
: children
) {
1461 switch (child
.getType()) {
1462 case CTFParser
.CTF_EXPRESSION_VAL
:
1464 * An assignment expression must have 2 children, left and
1468 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1469 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1471 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1473 if (!isAnyUnaryString(leftStrings
.get(0))) {
1474 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1476 String left
= concatenateUnaryStrings(leftStrings
);
1478 if (left
.equals(ENCODING
)) {
1479 encoding
= getEncoding(rightNode
);
1481 throw new ParseException("String: unknown attribute " //$NON-NLS-1$
1487 throw childTypeError(child
);
1491 stringDeclaration
= StringDeclaration
.getStringDeclaration(encoding
);
1494 return stringDeclaration
;
1498 * Parses a struct declaration and returns the corresponding declaration.
1502 * @return The corresponding struct declaration.
1503 * @throws ParseException
1505 private StructDeclaration
parseStruct(CommonTree struct
)
1506 throws ParseException
{
1508 List
<CommonTree
> children
= struct
.getChildren();
1510 /* The return value */
1511 StructDeclaration structDeclaration
= null;
1514 String structName
= null;
1515 boolean hasName
= false;
1518 CommonTree structBody
= null;
1519 boolean hasBody
= false;
1522 long structAlign
= 0;
1524 /* Loop on all children and identify what we have to work with. */
1525 for (CommonTree child
: children
) {
1526 switch (child
.getType()) {
1527 case CTFParser
.STRUCT_NAME
: {
1529 CommonTree structNameIdentifier
= (CommonTree
) child
.getChild(0);
1530 structName
= structNameIdentifier
.getText();
1533 case CTFParser
.STRUCT_BODY
: {
1539 case CTFParser
.ALIGN
: {
1540 CommonTree structAlignExpression
= (CommonTree
) child
.getChild(0);
1542 structAlign
= getAlignment(structAlignExpression
);
1546 throw childTypeError(child
);
1551 * If a struct has just a body and no name (just like the song,
1552 * "A Struct With No Name" by America (sorry for that...)), it's a
1553 * definition of a new type, so we create the type declaration and
1554 * return it. We can't add it to the declaration scope since there is no
1555 * name, but that's what we want because it won't be possible to use it
1556 * again to declare another field.
1558 * If it has just a name, we look it up in the declaration scope and
1559 * return the associated declaration. If it is not found in the
1560 * declaration scope, it means that a struct with that name has not been
1561 * declared, which is an error.
1563 * If it has both, then we create the type declaration and register it
1564 * to the current scope.
1566 * If it has none, then what are we doing here ?
1570 * If struct has a name, check if already defined in the current
1573 if (hasName
&& (getCurrentScope().lookupStruct(structName
) != null)) {
1574 throw new ParseException("struct " + structName
//$NON-NLS-1$
1575 + " already defined."); //$NON-NLS-1$
1577 /* Create the declaration */
1578 structDeclaration
= new StructDeclaration(structAlign
);
1580 /* Parse the body */
1581 parseStructBody(structBody
, structDeclaration
, structName
);
1583 /* If struct has name, add it to the current scope. */
1585 getCurrentScope().registerStruct(structName
, structDeclaration
);
1587 } else /* !hasBody */ {
1589 /* Name and !body */
1591 /* Lookup the name in the current scope. */
1592 structDeclaration
= getCurrentScope().lookupStructRecursive(structName
);
1595 * If not found, it means that a struct with such name has not
1598 if (structDeclaration
== null) {
1599 throw new ParseException("struct " + structName
//$NON-NLS-1$
1600 + " is not defined"); //$NON-NLS-1$
1603 /* !Name and !body */
1605 /* We can't do anything with that. */
1606 throw new ParseException("struct with no name and no body"); //$NON-NLS-1$
1609 return StructDeclarationFlattener
.tryFlattenStruct(structDeclaration
);
1613 * Parses a struct body, adding the fields to specified structure
1617 * A STRUCT_BODY node.
1618 * @param structDeclaration
1619 * The struct declaration.
1620 * @throws ParseException
1622 private void parseStructBody(CommonTree structBody
,
1623 StructDeclaration structDeclaration
, @Nullable String structName
) throws ParseException
{
1625 List
<CommonTree
> structDeclarations
= structBody
.getChildren();
1626 if (structDeclarations
== null) {
1627 structDeclarations
= Collections
.emptyList();
1631 * If structDeclaration is null, structBody has no children and the
1632 * struct body is empty.
1634 pushNamedScope(structName
, MetadataStrings
.STRUCT
);
1636 for (CommonTree declarationNode
: structDeclarations
) {
1637 switch (declarationNode
.getType()) {
1638 case CTFParser
.TYPEALIAS
:
1639 parseTypealias(declarationNode
);
1641 case CTFParser
.TYPEDEF
:
1642 parseTypedef(declarationNode
);
1644 case CTFParser
.SV_DECLARATION
:
1645 parseStructDeclaration(declarationNode
, structDeclaration
);
1648 throw childTypeError(declarationNode
);
1655 * Parses a declaration found in a struct.
1657 * @param declaration
1658 * A SV_DECLARATION node.
1660 * A struct declaration. (I know, little name clash here...)
1661 * @throws ParseException
1663 private void parseStructDeclaration(CommonTree declaration
,
1664 StructDeclaration struct
) throws ParseException
{
1666 /* Get the type specifier list node */
1667 CommonTree typeSpecifierListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_SPECIFIER_LIST
);
1669 /* Get the type declarator list node */
1670 CommonTree typeDeclaratorListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_DECLARATOR_LIST
);
1672 /* Get the type declarator list */
1673 List
<CommonTree
> typeDeclaratorList
= typeDeclaratorListNode
.getChildren();
1676 * For each type declarator, parse the declaration and add a field to
1679 for (CommonTree typeDeclaratorNode
: typeDeclaratorList
) {
1681 StringBuilder identifierSB
= new StringBuilder();
1683 IDeclaration decl
= parseTypeDeclarator(typeDeclaratorNode
,
1684 typeSpecifierListNode
, identifierSB
);
1685 String fieldName
= identifierSB
.toString();
1686 getCurrentScope().registerIdentifier(fieldName
, decl
);
1688 if (struct
.hasField(fieldName
)) {
1689 throw new ParseException("struct: duplicate field " //$NON-NLS-1$
1693 struct
.addField(fieldName
, decl
);
1699 * Parses an enum declaration and returns the corresponding declaration.
1703 * @return The corresponding enum declaration.
1704 * @throws ParseException
1706 private EnumDeclaration
parseEnum(CommonTree theEnum
) throws ParseException
{
1708 List
<CommonTree
> children
= theEnum
.getChildren();
1710 /* The return value */
1711 EnumDeclaration enumDeclaration
= null;
1714 String enumName
= null;
1717 CommonTree enumBody
= null;
1719 /* Container type */
1720 IntegerDeclaration containerTypeDeclaration
= null;
1722 /* Loop on all children and identify what we have to work with. */
1723 for (CommonTree child
: children
) {
1724 switch (child
.getType()) {
1725 case CTFParser
.ENUM_NAME
: {
1726 CommonTree enumNameIdentifier
= (CommonTree
) child
.getChild(0);
1727 enumName
= enumNameIdentifier
.getText();
1730 case CTFParser
.ENUM_BODY
: {
1734 case CTFParser
.ENUM_CONTAINER_TYPE
: {
1735 containerTypeDeclaration
= parseEnumContainerType(child
);
1739 throw childTypeError(child
);
1744 * If the container type has not been defined explicitly, we assume it
1747 if (containerTypeDeclaration
== null) {
1748 IDeclaration enumDecl
;
1750 * it could be because the enum was already declared.
1752 if (enumName
!= null) {
1753 getCurrentScope().setName(enumName
);
1754 enumDecl
= getCurrentScope().lookupEnumRecursive(enumName
);
1755 if (enumDecl
!= null) {
1756 return (EnumDeclaration
) enumDecl
;
1760 IDeclaration decl
= getCurrentScope().lookupTypeRecursive("int"); //$NON-NLS-1$
1763 throw new ParseException("enum container type implicit and type int not defined"); //$NON-NLS-1$
1764 } else if (!(decl
instanceof IntegerDeclaration
)) {
1765 throw new ParseException("enum container type implicit and type int not an integer"); //$NON-NLS-1$
1768 containerTypeDeclaration
= (IntegerDeclaration
) decl
;
1772 * If it has a body, it's a new declaration, otherwise it's a reference
1773 * to an existing declaration. Same logic as struct.
1775 if (enumBody
!= null) {
1777 * If enum has a name, check if already defined in the current
1780 if ((enumName
!= null)
1781 && (getCurrentScope().lookupEnum(enumName
) != null)) {
1782 throw new ParseException("enum " + enumName
//$NON-NLS-1$
1783 + " already defined"); //$NON-NLS-1$
1786 /* Create the declaration */
1787 enumDeclaration
= new EnumDeclaration(containerTypeDeclaration
);
1789 /* Parse the body */
1790 parseEnumBody(enumBody
, enumDeclaration
, enumName
);
1792 /* If the enum has name, add it to the current scope. */
1793 if (enumName
!= null) {
1794 getCurrentScope().registerEnum(enumName
, enumDeclaration
);
1797 if (enumName
!= null) {
1798 /* Name and !body */
1800 /* Lookup the name in the current scope. */
1801 enumDeclaration
= getCurrentScope().lookupEnumRecursive(enumName
);
1804 * If not found, it means that an enum with such name has not
1807 if (enumDeclaration
== null) {
1808 throw new ParseException("enum " + enumName
//$NON-NLS-1$
1809 + " is not defined"); //$NON-NLS-1$
1812 /* !Name and !body */
1813 throw new ParseException("enum with no name and no body"); //$NON-NLS-1$
1817 return enumDeclaration
;
1822 * Parses an enum body, adding the enumerators to the specified enum
1826 * An ENUM_BODY node.
1827 * @param enumDeclaration
1828 * The enum declaration.
1829 * @throws ParseException
1831 private void parseEnumBody(CommonTree enumBody
,
1832 EnumDeclaration enumDeclaration
, @Nullable String enumName
) throws ParseException
{
1834 List
<CommonTree
> enumerators
= enumBody
.getChildren();
1835 /* enum body can't be empty (unlike struct). */
1837 pushNamedScope(enumName
, MetadataStrings
.ENUM
);
1840 * Start at -1, so that if the first enumrator has no explicit value, it
1845 for (CommonTree enumerator
: enumerators
) {
1846 lastHigh
= parseEnumEnumerator(enumerator
, enumDeclaration
,
1855 * Parses an enumerator node and adds an enumerator declaration to an
1856 * enumeration declaration.
1858 * The high value of the range of the last enumerator is needed in case the
1859 * current enumerator does not specify its value.
1862 * An ENUM_ENUMERATOR node.
1863 * @param enumDeclaration
1864 * en enumeration declaration to which will be added the
1867 * The high value of the range of the last enumerator
1868 * @return The high value of the value range of the current enumerator.
1869 * @throws ParseException
1871 private static long parseEnumEnumerator(CommonTree enumerator
,
1872 EnumDeclaration enumDeclaration
, long lastHigh
)
1873 throws ParseException
{
1875 List
<CommonTree
> children
= enumerator
.getChildren();
1877 long low
= 0, high
= 0;
1878 boolean valueSpecified
= false;
1879 String label
= null;
1881 for (CommonTree child
: children
) {
1882 if (isAnyUnaryString(child
)) {
1883 label
= parseUnaryString(child
);
1884 } else if (child
.getType() == CTFParser
.ENUM_VALUE
) {
1886 valueSpecified
= true;
1888 low
= parseUnaryInteger((CommonTree
) child
.getChild(0));
1890 } else if (child
.getType() == CTFParser
.ENUM_VALUE_RANGE
) {
1892 valueSpecified
= true;
1894 low
= parseUnaryInteger((CommonTree
) child
.getChild(0));
1895 high
= parseUnaryInteger((CommonTree
) child
.getChild(1));
1897 throw childTypeError(child
);
1901 if (!valueSpecified
) {
1907 throw new ParseException("enum low value greater than high value"); //$NON-NLS-1$
1910 if (!enumDeclaration
.add(low
, high
, label
)) {
1911 throw new ParseException("enum declarator values overlap."); //$NON-NLS-1$
1914 if (valueSpecified
&& (BigInteger
.valueOf(low
).compareTo(enumDeclaration
.getContainerType().getMinValue()) == -1 ||
1915 BigInteger
.valueOf(high
).compareTo(enumDeclaration
.getContainerType().getMaxValue()) == 1)) {
1916 throw new ParseException("enum value is not in range"); //$NON-NLS-1$
1923 * Parses an enum container type node and returns the corresponding integer
1926 * @param enumContainerType
1927 * An ENUM_CONTAINER_TYPE node.
1928 * @return An integer declaration corresponding to the container type.
1929 * @throws ParseException
1930 * If the type does not parse correctly or if it is not an
1933 private IntegerDeclaration
parseEnumContainerType(
1934 CommonTree enumContainerType
) throws ParseException
{
1936 /* Get the child, which should be a type specifier list */
1937 CommonTree typeSpecifierList
= (CommonTree
) enumContainerType
.getChild(0);
1939 /* Parse it and get the corresponding declaration */
1940 IDeclaration decl
= parseTypeSpecifierList(typeSpecifierList
, null);
1942 /* If is is an integer, return it, else throw an error */
1943 if (decl
instanceof IntegerDeclaration
) {
1944 return (IntegerDeclaration
) decl
;
1946 throw new ParseException("enum container type must be an integer"); //$NON-NLS-1$
1949 private VariantDeclaration
parseVariant(CommonTree variant
)
1950 throws ParseException
{
1952 List
<CommonTree
> children
= variant
.getChildren();
1953 VariantDeclaration variantDeclaration
= null;
1955 boolean hasName
= false;
1956 String variantName
= null;
1958 boolean hasBody
= false;
1959 CommonTree variantBody
= null;
1961 boolean hasTag
= false;
1962 String variantTag
= null;
1964 for (CommonTree child
: children
) {
1965 switch (child
.getType()) {
1966 case CTFParser
.VARIANT_NAME
:
1970 CommonTree variantNameIdentifier
= (CommonTree
) child
.getChild(0);
1972 variantName
= variantNameIdentifier
.getText();
1975 case CTFParser
.VARIANT_TAG
:
1979 CommonTree variantTagIdentifier
= (CommonTree
) child
.getChild(0);
1981 variantTag
= variantTagIdentifier
.getText();
1984 case CTFParser
.VARIANT_BODY
:
1988 variantBody
= child
;
1992 throw childTypeError(child
);
1998 * If variant has a name, check if already defined in the current
2002 && (getCurrentScope().lookupVariant(variantName
) != null)) {
2003 throw new ParseException("variant " + variantName
//$NON-NLS-1$
2004 + " already defined."); //$NON-NLS-1$
2007 /* Create the declaration */
2008 variantDeclaration
= new VariantDeclaration();
2010 /* Parse the body */
2011 parseVariantBody(variantBody
, variantDeclaration
, variantName
);
2013 /* If variant has name, add it to the current scope. */
2015 getCurrentScope().registerVariant(variantName
,
2016 variantDeclaration
);
2018 } else /* !hasBody */ {
2020 /* Name and !body */
2022 /* Lookup the name in the current scope. */
2023 variantDeclaration
= getCurrentScope().lookupVariantRecursive(
2027 * If not found, it means that a struct with such name has not
2030 if (variantDeclaration
== null) {
2031 throw new ParseException("variant " + variantName
//$NON-NLS-1$
2032 + " is not defined"); //$NON-NLS-1$
2035 /* !Name and !body */
2037 /* We can't do anything with that. */
2038 throw new ParseException("variant with no name and no body"); //$NON-NLS-1$
2043 variantDeclaration
.setTag(variantTag
);
2045 IDeclaration decl
= getCurrentScope().lookupIdentifierRecursive(variantTag
);
2047 throw new ParseException("Variant tag not found: " + variantTag
); //$NON-NLS-1$
2049 if (!(decl
instanceof EnumDeclaration
)) {
2050 throw new ParseException("Variant tag must be an enum: " + variantTag
); //$NON-NLS-1$
2052 EnumDeclaration tagDecl
= (EnumDeclaration
) decl
;
2053 Set
<String
> intersection
= new HashSet
<>(tagDecl
.getLabels());
2054 intersection
.retainAll(variantDeclaration
.getFields().keySet());
2055 if (intersection
.isEmpty()) {
2056 throw new ParseException("Variant contains no values of the tag, impossible to use: " + variantName
); //$NON-NLS-1$
2060 return variantDeclaration
;
2063 private void parseVariantBody(CommonTree variantBody
,
2064 VariantDeclaration variantDeclaration
, @Nullable String variantName
) throws ParseException
{
2066 List
<CommonTree
> variantDeclarations
= variantBody
.getChildren();
2068 pushNamedScope(variantName
, MetadataStrings
.VARIANT
);
2070 for (CommonTree declarationNode
: variantDeclarations
) {
2071 switch (declarationNode
.getType()) {
2072 case CTFParser
.TYPEALIAS
:
2073 parseTypealias(declarationNode
);
2075 case CTFParser
.TYPEDEF
:
2076 parseTypedef(declarationNode
);
2078 case CTFParser
.SV_DECLARATION
:
2079 parseVariantDeclaration(declarationNode
, variantDeclaration
);
2082 throw childTypeError(declarationNode
);
2089 private void parseVariantDeclaration(CommonTree declaration
,
2090 VariantDeclaration variant
) throws ParseException
{
2092 /* Get the type specifier list node */
2093 CommonTree typeSpecifierListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_SPECIFIER_LIST
);
2095 /* Get the type declarator list node */
2096 CommonTree typeDeclaratorListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_DECLARATOR_LIST
);
2098 /* Get the type declarator list */
2099 List
<CommonTree
> typeDeclaratorList
= typeDeclaratorListNode
.getChildren();
2102 * For each type declarator, parse the declaration and add a field to
2105 for (CommonTree typeDeclaratorNode
: typeDeclaratorList
) {
2107 StringBuilder identifierSB
= new StringBuilder();
2109 IDeclaration decl
= parseTypeDeclarator(typeDeclaratorNode
,
2110 typeSpecifierListNode
, identifierSB
);
2112 String name
= identifierSB
.toString();
2114 if (variant
.hasField(name
)) {
2115 throw new ParseException("variant: duplicate field " //$NON-NLS-1$
2119 getCurrentScope().registerIdentifier(name
, decl
);
2121 variant
.addField(name
, decl
);
2126 * Creates the string representation of a type declaration (type specifier
2129 * @param typeSpecifierList
2130 * A TYPE_SPECIFIER_LIST node.
2132 * A list of POINTER nodes.
2133 * @return The string representation.
2134 * @throws ParseException
2136 private static String
createTypeDeclarationString(
2137 CommonTree typeSpecifierList
, List
<CommonTree
> pointers
)
2138 throws ParseException
{
2139 StringBuilder sb
= new StringBuilder();
2141 createTypeSpecifierListString(typeSpecifierList
, sb
);
2142 createPointerListString(pointers
, sb
);
2144 return sb
.toString();
2148 * Creates the string representation of a list of type specifiers.
2150 * @param typeSpecifierList
2151 * A TYPE_SPECIFIER_LIST node.
2153 * A StringBuilder to which will be appended the string.
2154 * @throws ParseException
2156 private static void createTypeSpecifierListString(
2157 CommonTree typeSpecifierList
, StringBuilder sb
)
2158 throws ParseException
{
2160 List
<CommonTree
> children
= typeSpecifierList
.getChildren();
2162 boolean firstItem
= true;
2164 for (CommonTree child
: children
) {
2172 /* Append the string that represents this type specifier. */
2173 createTypeSpecifierString(child
, sb
);
2178 * Creates the string representation of a type specifier.
2180 * @param typeSpecifier
2181 * A TYPE_SPECIFIER node.
2183 * A StringBuilder to which will be appended the string.
2184 * @throws ParseException
2186 private static void createTypeSpecifierString(CommonTree typeSpecifier
,
2187 StringBuilder sb
) throws ParseException
{
2188 switch (typeSpecifier
.getType()) {
2189 case CTFParser
.FLOATTOK
:
2190 case CTFParser
.INTTOK
:
2191 case CTFParser
.LONGTOK
:
2192 case CTFParser
.SHORTTOK
:
2193 case CTFParser
.SIGNEDTOK
:
2194 case CTFParser
.UNSIGNEDTOK
:
2195 case CTFParser
.CHARTOK
:
2196 case CTFParser
.DOUBLETOK
:
2197 case CTFParser
.VOIDTOK
:
2198 case CTFParser
.BOOLTOK
:
2199 case CTFParser
.COMPLEXTOK
:
2200 case CTFParser
.IMAGINARYTOK
:
2201 case CTFParser
.CONSTTOK
:
2202 case CTFParser
.IDENTIFIER
:
2203 sb
.append(typeSpecifier
.getText());
2205 case CTFParser
.STRUCT
: {
2206 CommonTree structName
= (CommonTree
) typeSpecifier
.getFirstChildWithType(CTFParser
.STRUCT_NAME
);
2207 if (structName
== null) {
2208 throw new ParseException("nameless struct found in createTypeSpecifierString"); //$NON-NLS-1$
2211 CommonTree structNameIdentifier
= (CommonTree
) structName
.getChild(0);
2213 sb
.append(structNameIdentifier
.getText());
2216 case CTFParser
.VARIANT
: {
2217 CommonTree variantName
= (CommonTree
) typeSpecifier
.getFirstChildWithType(CTFParser
.VARIANT_NAME
);
2218 if (variantName
== null) {
2219 throw new ParseException("nameless variant found in createTypeSpecifierString"); //$NON-NLS-1$
2222 CommonTree variantNameIdentifier
= (CommonTree
) variantName
.getChild(0);
2224 sb
.append(variantNameIdentifier
.getText());
2227 case CTFParser
.ENUM
: {
2228 CommonTree enumName
= (CommonTree
) typeSpecifier
.getFirstChildWithType(CTFParser
.ENUM_NAME
);
2229 if (enumName
== null) {
2230 throw new ParseException("nameless enum found in createTypeSpecifierString"); //$NON-NLS-1$
2233 CommonTree enumNameIdentifier
= (CommonTree
) enumName
.getChild(0);
2235 sb
.append(enumNameIdentifier
.getText());
2238 case CTFParser
.FLOATING_POINT
:
2239 case CTFParser
.INTEGER
:
2240 case CTFParser
.STRING
:
2241 throw new ParseException("CTF type found in createTypeSpecifierString"); //$NON-NLS-1$
2243 throw childTypeError(typeSpecifier
);
2248 * Creates the string representation of a list of pointers.
2250 * @param pointerList
2251 * A list of pointer nodes. If pointerList is null, this function
2254 * A stringbuilder to which will be appended the string.
2256 private static void createPointerListString(List
<CommonTree
> pointerList
,
2258 if (pointerList
== null) {
2262 for (CommonTree pointer
: pointerList
) {
2264 sb
.append(" *"); //$NON-NLS-1$
2265 if (pointer
.getChildCount() > 0) {
2267 sb
.append(" const"); //$NON-NLS-1$
2274 * The node to check.
2275 * @return True if the given node is an unary string.
2277 private static boolean isUnaryString(CommonTree node
) {
2278 return ((node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING
));
2283 * The node to check.
2284 * @return True if the given node is any type of unary string (no quotes,
2287 private static boolean isAnyUnaryString(CommonTree node
) {
2288 return ((node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING
) || (node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING_QUOTES
));
2293 * The node to check.
2294 * @return True if the given node is an unary integer.
2296 private static boolean isUnaryInteger(CommonTree node
) {
2297 return ((node
.getType() == CTFParser
.UNARY_EXPRESSION_DEC
) ||
2298 (node
.getType() == CTFParser
.UNARY_EXPRESSION_HEX
) || (node
.getType() == CTFParser
.UNARY_EXPRESSION_OCT
));
2302 * Parses a unary string node and return the string value.
2304 * @param unaryString
2305 * The unary string node to parse (type UNARY_EXPRESSION_STRING
2306 * or UNARY_EXPRESSION_STRING_QUOTES).
2307 * @return The string value.
2310 * It would be really nice to remove the quotes earlier, such as in the
2313 private static String
parseUnaryString(CommonTree unaryString
) {
2315 CommonTree value
= (CommonTree
) unaryString
.getChild(0);
2316 String strval
= value
.getText();
2319 if (unaryString
.getType() == CTFParser
.UNARY_EXPRESSION_STRING_QUOTES
) {
2320 strval
= strval
.substring(1, strval
.length() - 1);
2327 * Parses an unary integer (dec, hex or oct).
2329 * @param unaryInteger
2330 * An unary integer node.
2331 * @return The integer value.
2332 * @throws ParseException
2333 * on an invalid integer format ("bob" for example)
2335 private static long parseUnaryInteger(CommonTree unaryInteger
) throws ParseException
{
2337 List
<CommonTree
> children
= unaryInteger
.getChildren();
2338 CommonTree value
= children
.get(0);
2339 String strval
= value
.getText();
2343 intval
= Long
.decode(strval
);
2344 } catch (NumberFormatException e
) {
2345 throw new ParseException("Invalid integer format: " + strval
, e
); //$NON-NLS-1$
2348 /* The rest of children are sign */
2349 if ((children
.size() % 2) == 0) {
2355 private static long getMajorOrMinor(CommonTree rightNode
)
2356 throws ParseException
{
2358 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2360 if (isUnaryInteger(firstChild
)) {
2361 if (rightNode
.getChildCount() > 1) {
2362 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2365 long m
= parseUnaryInteger(firstChild
);
2368 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2373 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2376 private static UUID
getUUID(CommonTree rightNode
) throws ParseException
{
2378 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2380 if (isAnyUnaryString(firstChild
)) {
2381 if (rightNode
.getChildCount() > 1) {
2382 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2385 String uuidstr
= parseUnaryString(firstChild
);
2388 return UUID
.fromString(uuidstr
);
2389 } catch (IllegalArgumentException e
) {
2390 throw new ParseException("Invalid format for UUID", e
); //$NON-NLS-1$
2393 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2397 * Gets the value of a "signed" integer attribute.
2401 * @return The "signed" value as a boolean.
2402 * @throws ParseException
2404 private static boolean getSigned(CommonTree rightNode
)
2405 throws ParseException
{
2407 boolean ret
= false;
2408 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2410 if (isUnaryString(firstChild
)) {
2411 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
2413 if (strval
.equals(MetadataStrings
.TRUE
)
2414 || strval
.equals(MetadataStrings
.TRUE2
)) {
2416 } else if (strval
.equals(MetadataStrings
.FALSE
)
2417 || strval
.equals(MetadataStrings
.FALSE2
)) {
2420 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2421 + firstChild
.getChild(0).getText());
2423 } else if (isUnaryInteger(firstChild
)) {
2424 /* Happens if the value is something like "1234.hello" */
2425 if (rightNode
.getChildCount() > 1) {
2426 throw new ParseException("Invalid boolean value"); //$NON-NLS-1$
2429 long intval
= parseUnaryInteger(firstChild
);
2433 } else if (intval
== 0) {
2436 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2437 + firstChild
.getChild(0).getText());
2440 throw new ParseException();
2447 * Gets the value of a "byte_order" integer attribute.
2451 * @return The "byte_order" value.
2452 * @throws ParseException
2454 private ByteOrder
getByteOrder(CommonTree rightNode
) throws ParseException
{
2456 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2458 if (isUnaryString(firstChild
)) {
2459 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
2461 if (strval
.equals(MetadataStrings
.LE
)) {
2462 return ByteOrder
.LITTLE_ENDIAN
;
2463 } else if (strval
.equals(MetadataStrings
.BE
)
2464 || strval
.equals(MetadataStrings
.NETWORK
)) {
2465 return ByteOrder
.BIG_ENDIAN
;
2466 } else if (strval
.equals(MetadataStrings
.NATIVE
)) {
2467 return fTrace
.getByteOrder();
2469 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2472 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2476 * Determines if the given value is a valid alignment value.
2479 * The value to check.
2480 * @return True if it is valid.
2482 private static boolean isValidAlignment(long alignment
) {
2483 return !((alignment
<= 0) || ((alignment
& (alignment
- 1)) != 0));
2487 * Gets the value of a "size" integer attribute.
2491 * @return The "size" value.
2492 * @throws ParseException
2494 private static long getSize(CommonTree rightNode
) throws ParseException
{
2496 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2498 if (isUnaryInteger(firstChild
)) {
2499 if (rightNode
.getChildCount() > 1) {
2500 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2503 long size
= parseUnaryInteger(firstChild
);
2506 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2511 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2515 * Gets the value of a "align" integer or struct attribute.
2518 * A CTF_RIGHT node or directly an unary integer.
2519 * @return The align value.
2520 * @throws ParseException
2522 private static long getAlignment(CommonTree node
) throws ParseException
{
2525 * If a CTF_RIGHT node was passed, call getAlignment with the first
2528 if (node
.getType() == CTFParser
.CTF_RIGHT
) {
2529 if (node
.getChildCount() > 1) {
2530 throw new ParseException("Invalid alignment value"); //$NON-NLS-1$
2533 return getAlignment((CommonTree
) node
.getChild(0));
2534 } else if (isUnaryInteger(node
)) {
2535 long alignment
= parseUnaryInteger(node
);
2537 if (!isValidAlignment(alignment
)) {
2538 throw new ParseException("Invalid value for alignment : " //$NON-NLS-1$
2544 throw new ParseException("Invalid value for alignment"); //$NON-NLS-1$
2548 * Gets the value of a "base" integer attribute.
2551 * An CTF_RIGHT node.
2552 * @return The "base" value.
2553 * @throws ParseException
2555 private static int getBase(CommonTree rightNode
) throws ParseException
{
2557 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2559 if (isUnaryInteger(firstChild
)) {
2560 if (rightNode
.getChildCount() > 1) {
2561 throw new ParseException("invalid base value"); //$NON-NLS-1$
2564 long intval
= parseUnaryInteger(firstChild
);
2565 if ((intval
== INTEGER_BASE_2
) || (intval
== INTEGER_BASE_8
) || (intval
== INTEGER_BASE_10
)
2566 || (intval
== INTEGER_BASE_16
)) {
2567 return (int) intval
;
2569 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2570 } else if (isUnaryString(firstChild
)) {
2571 switch (concatenateUnaryStrings(rightNode
.getChildren())) {
2572 case MetadataStrings
.DECIMAL
:
2573 case MetadataStrings
.DEC
:
2574 case MetadataStrings
.DEC_CTE
:
2575 case MetadataStrings
.INT_MOD
:
2576 case MetadataStrings
.UNSIGNED_CTE
:
2577 return INTEGER_BASE_10
;
2578 case MetadataStrings
.HEXADECIMAL
:
2579 case MetadataStrings
.HEX
:
2580 case MetadataStrings
.X
:
2581 case MetadataStrings
.X2
:
2582 case MetadataStrings
.POINTER
:
2583 return INTEGER_BASE_16
;
2584 case MetadataStrings
.OCT
:
2585 case MetadataStrings
.OCTAL
:
2586 case MetadataStrings
.OCTAL_CTE
:
2587 return INTEGER_BASE_8
;
2588 case MetadataStrings
.BIN
:
2589 case MetadataStrings
.BINARY
:
2590 return INTEGER_BASE_2
;
2592 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2595 throw new ParseException("invalid value for base"); //$NON-NLS-1$
2600 * Gets the value of an "encoding" integer attribute.
2604 * @return The "encoding" value.
2605 * @throws ParseException
2608 private static Encoding
getEncoding(CommonTree rightNode
)
2609 throws ParseException
{
2611 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2613 if (isUnaryString(firstChild
)) {
2614 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
2616 if (strval
.equals(MetadataStrings
.UTF8
)) {
2617 return Encoding
.UTF8
;
2618 } else if (strval
.equals(MetadataStrings
.ASCII
)) {
2619 return Encoding
.ASCII
;
2620 } else if (strval
.equals(MetadataStrings
.NONE
)) {
2621 return Encoding
.NONE
;
2623 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2626 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2629 private static long getStreamID(CommonTree rightNode
) throws ParseException
{
2631 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2633 if (isUnaryInteger(firstChild
)) {
2634 if (rightNode
.getChildCount() > 1) {
2635 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2638 long intval
= parseUnaryInteger(firstChild
);
2642 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2645 private static String
getEventName(CommonTree rightNode
)
2646 throws ParseException
{
2648 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2650 if (isAnyUnaryString(firstChild
)) {
2651 String str
= concatenateUnaryStrings(rightNode
.getChildren());
2655 throw new ParseException("invalid value for event name"); //$NON-NLS-1$
2658 private static long getEventID(CommonTree rightNode
) throws ParseException
{
2660 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2662 if (isUnaryInteger(firstChild
)) {
2663 if (rightNode
.getChildCount() > 1) {
2664 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2667 long intval
= parseUnaryInteger(firstChild
);
2668 if (intval
> Integer
.MAX_VALUE
) {
2669 throw new ParseException("Event id larger than int.maxvalue, something is amiss"); //$NON-NLS-1$
2673 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2677 * Concatenates a list of unary strings separated by arrows (->) or dots.
2680 * A list, first element being an unary string, subsequent
2681 * elements being ARROW or DOT nodes with unary strings as child.
2682 * @return The string representation of the unary string chain.
2684 private static String
concatenateUnaryStrings(List
<CommonTree
> strings
) {
2686 StringBuilder sb
= new StringBuilder();
2688 CommonTree first
= strings
.get(0);
2689 sb
.append(parseUnaryString(first
));
2691 boolean isFirst
= true;
2693 for (CommonTree ref
: strings
) {
2699 CommonTree id
= (CommonTree
) ref
.getChild(0);
2701 if (ref
.getType() == CTFParser
.ARROW
) {
2702 sb
.append("->"); //$NON-NLS-1$
2707 sb
.append(parseUnaryString(id
));
2710 return sb
.toString();
2714 * Throws a ParseException stating that the parent-child relation between
2715 * the given node and its parent is not valid. It means that the shape of
2716 * the AST is unexpected.
2719 * The invalid child node.
2720 * @return ParseException with details
2722 private static ParseException
childTypeError(CommonTree child
) {
2723 CommonTree parent
= (CommonTree
) child
.getParent();
2724 String error
= "Parent " + CTFParser
.tokenNames
[parent
.getType()] //$NON-NLS-1$
2725 + " can't have a child of type " //$NON-NLS-1$
2726 + CTFParser
.tokenNames
[child
.getType()] + "."; //$NON-NLS-1$
2728 return new ParseException(error
);
2731 // ------------------------------------------------------------------------
2733 // ------------------------------------------------------------------------
2736 * Adds a new declaration scope on the top of the scope stack.
2738 private void pushScope(String name
) {
2739 fScope
= new DeclarationScope(fScope
, name
);
2743 * Removes the top declaration scope from the scope stack.
2745 private void popScope() {
2746 fScope
= fScope
.getParentScope();
2749 private void pushNamedScope(@Nullable String name
, String defaultName
) {
2750 pushScope(name
== null ? defaultName
: name
);
2754 * Returns the current declaration scope.
2756 * @return The current declaration scope.
2758 private DeclarationScope
getCurrentScope() {