1 /*******************************************************************************
2 * Copyright (c) 2011, 2014 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
.tracecompass
.ctf
.core
.event
.CTFClock
;
31 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.Encoding
;
32 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.EnumDeclaration
;
33 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.FloatDeclaration
;
34 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IDeclaration
;
35 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IEventHeaderDeclaration
;
36 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IntegerDeclaration
;
37 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.StringDeclaration
;
38 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.StructDeclaration
;
39 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.VariantDeclaration
;
40 import org
.eclipse
.tracecompass
.ctf
.core
.trace
.CTFStream
;
41 import org
.eclipse
.tracecompass
.ctf
.core
.trace
.CTFTrace
;
42 import org
.eclipse
.tracecompass
.ctf
.parser
.CTFParser
;
43 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.Activator
;
44 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.EventDeclaration
;
45 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
.exceptions
.ParseException
;
46 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.ArrayDeclaration
;
47 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.SequenceDeclaration
;
48 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.StructDeclarationFlattener
;
49 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.composite
.EventHeaderCompactDeclaration
;
50 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.composite
.EventHeaderLargeDeclaration
;
55 public class IOStructGen
{
57 // ------------------------------------------------------------------------
59 // ------------------------------------------------------------------------
61 private static final @NonNull String MAP
= "map"; //$NON-NLS-1$
62 private static final @NonNull String ENCODING
= "encoding"; //$NON-NLS-1$
63 private static final @NonNull String BASE
= "base"; //$NON-NLS-1$
64 private static final @NonNull String SIZE
= "size"; //$NON-NLS-1$
65 private static final @NonNull String SIGNED
= "signed"; //$NON-NLS-1$
66 private static final @NonNull String LINE
= "line"; //$NON-NLS-1$
67 private static final @NonNull String FILE
= "file"; //$NON-NLS-1$
68 private static final @NonNull String IP
= "ip"; //$NON-NLS-1$
69 private static final @NonNull String FUNC
= "func"; //$NON-NLS-1$
70 private static final @NonNull String NAME
= "name"; //$NON-NLS-1$
71 private static final @NonNull String EMPTY_STRING
= ""; //$NON-NLS-1$
72 private static final int INTEGER_BASE_16
= 16;
73 private static final int INTEGER_BASE_10
= 10;
74 private static final int INTEGER_BASE_8
= 8;
75 private static final int INTEGER_BASE_2
= 2;
76 private static final long DEFAULT_ALIGNMENT
= 8;
77 private static final int DEFAULT_FLOAT_EXPONENT
= 8;
78 private static final int DEFAULT_FLOAT_MANTISSA
= 24;
79 private static final int DEFAULT_INT_BASE
= 10;
83 private final CTFTrace fTrace
;
84 private CommonTree fTree
;
87 * The current declaration scope.
89 private DeclarationScope fScope
= null;
92 * Data helpers needed for streaming
95 private boolean fHasBeenParsed
= false;
97 // ------------------------------------------------------------------------
99 // ------------------------------------------------------------------------
105 * the tree (ANTLR generated) with the parsed TSDL data.
107 * the trace containing the places to put all the read metadata
109 public IOStructGen(CommonTree tree
, CTFTrace trace
) {
116 * Parse the tree and populate the trace defined in the constructor.
118 * @throws ParseException
119 * If there was a problem parsing the metadata
121 public void generate() throws ParseException
{
126 * Parse a partial tree and populate the trace defined in the constructor.
127 * Does not check for a "trace" block as there is only one in the trace and
130 * @throws ParseException
131 * If there was a problem parsing the metadata
133 public void generateFragment() throws ParseException
{
134 parseIncompleteRoot(fTree
);
137 // ------------------------------------------------------------------------
139 // ------------------------------------------------------------------------
142 * Sets a new tree to parse
145 * the new tree to parse
147 public void setTree(CommonTree newTree
) {
152 * Parse the root node.
156 * @throws ParseException
158 private void parseRoot(CommonTree root
) throws ParseException
{
160 List
<CommonTree
> children
= root
.getChildren();
162 CommonTree traceNode
= null;
163 List
<CommonTree
> streams
= new ArrayList
<>();
164 List
<CommonTree
> events
= new ArrayList
<>();
165 List
<CommonTree
> declarations
= new ArrayList
<>();
166 List
<CommonTree
> environments
= new ArrayList
<>();
167 List
<CommonTree
> clocks
= new ArrayList
<>();
168 List
<CommonTree
> callsites
= new ArrayList
<>();
170 /* Create a new declaration scope with no parent. */
173 for (CommonTree child
: children
) {
174 final int type
= child
.getType();
176 case CTFParser
.DECLARATION
:
177 declarations
.add(child
);
179 case CTFParser
.TRACE
:
180 if (traceNode
!= null) {
181 throw new ParseException("Only one trace block is allowed"); //$NON-NLS-1$
185 case CTFParser
.STREAM
:
188 case CTFParser
.EVENT
:
191 case CTFParser
.CLOCK
:
195 environments
.add(child
);
197 case CTFParser
.CALLSITE
:
198 callsites
.add(child
);
201 childTypeError(child
);
204 for (CommonTree decl
: declarations
) {
205 parseRootDeclaration(decl
);
207 if (traceNode
== null) {
208 throw new ParseException("Missing trace block"); //$NON-NLS-1$
211 parseTrace(traceNode
);
213 for (CommonTree environment
: environments
) {
214 parseEnvironment(environment
);
216 for (CommonTree clock
: clocks
) {
219 for (CommonTree callsite
: callsites
) {
220 parseCallsite(callsite
);
223 if (!streams
.isEmpty()) {
224 for (CommonTree stream
: streams
) {
228 /* Add an empty stream that will have a null id */
229 fTrace
.addStream(new CTFStream(fTrace
));
232 for (CommonTree event
: events
) {
236 fHasBeenParsed
= true;
239 private void parseIncompleteRoot(CommonTree root
) throws ParseException
{
240 List
<CommonTree
> children
= root
.getChildren();
242 if (!fHasBeenParsed
) {
243 throw new ParseException("You need to run generate first"); //$NON-NLS-1$
245 List
<CommonTree
> streams
= new ArrayList
<>();
246 List
<CommonTree
> events
= new ArrayList
<>();
247 List
<CommonTree
> declarations
= new ArrayList
<>();
248 List
<CommonTree
> environments
= new ArrayList
<>();
249 List
<CommonTree
> clocks
= new ArrayList
<>();
250 List
<CommonTree
> callsites
= new ArrayList
<>();
251 /* Create a new declaration scope with no parent. */
254 for (CommonTree child
: children
) {
255 final int type
= child
.getType();
257 case CTFParser
.DECLARATION
:
258 declarations
.add(child
);
260 case CTFParser
.TRACE
:
261 throw new ParseException("Trace block defined here, please use generate and not generateFragment to parse this fragment"); //$NON-NLS-1$
262 case CTFParser
.STREAM
:
265 case CTFParser
.EVENT
:
268 case CTFParser
.CLOCK
:
272 environments
.add(child
);
274 case CTFParser
.CALLSITE
:
275 callsites
.add(child
);
278 childTypeError(child
);
281 for (CommonTree decl
: declarations
) {
282 parseRootDeclaration(decl
);
285 for (CommonTree environment
: environments
) {
286 parseEnvironment(environment
);
288 for (CommonTree clock
: clocks
) {
291 for (CommonTree callsite
: callsites
) {
292 parseCallsite(callsite
);
295 for (CommonTree stream
: streams
) {
299 for (CommonTree event
: events
) {
305 private void parseCallsite(CommonTree callsite
) {
307 List
<CommonTree
> children
= callsite
.getChildren();
309 String funcName
= null;
310 long lineNumber
= -1;
312 String fileName
= null;
314 for (CommonTree child
: children
) {
316 /* this is a regex to find the leading and trailing quotes */
317 final String regex
= "^\"|\"$"; //$NON-NLS-1$
319 * this is to replace the previous quotes with nothing...
320 * effectively deleting them
322 final String nullString
= EMPTY_STRING
;
323 left
= child
.getChild(0).getChild(0).getChild(0).getText();
324 if (left
.equals(NAME
)) {
325 name
= child
.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex
, nullString
);
326 } else if (left
.equals(FUNC
)) {
327 funcName
= child
.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex
, nullString
);
328 } else if (left
.equals(IP
)) {
329 ip
= Long
.decode(child
.getChild(1).getChild(0).getChild(0).getText());
330 } else if (left
.equals(FILE
)) {
331 fileName
= child
.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex
, nullString
);
332 } else if (left
.equals(LINE
)) {
333 lineNumber
= Long
.parseLong(child
.getChild(1).getChild(0).getChild(0).getText());
336 fTrace
.addCallsite(name
, funcName
, ip
, fileName
, lineNumber
);
339 private void parseEnvironment(CommonTree environment
) {
340 List
<CommonTree
> children
= environment
.getChildren();
341 for (CommonTree child
: children
) {
344 left
= child
.getChild(0).getChild(0).getChild(0).getText();
345 right
= child
.getChild(1).getChild(0).getChild(0).getText();
346 fTrace
.addEnvironmentVar(left
, right
);
350 private void parseClock(CommonTree clock
) throws ParseException
{
351 List
<CommonTree
> children
= clock
.getChildren();
352 CTFClock ctfClock
= new CTFClock();
353 for (CommonTree child
: children
) {
354 final String key
= child
.getChild(0).getChild(0).getChild(0).getText();
355 final CommonTree value
= (CommonTree
) child
.getChild(1).getChild(0).getChild(0);
356 final int type
= value
.getType();
357 final String text
= value
.getText();
359 case CTFParser
.INTEGER
:
360 case CTFParser
.DECIMAL_LITERAL
:
362 * Not a pretty hack, this is to make sure that there is no
363 * number overflow due to 63 bit integers. The offset should
364 * only really be an issue in the year 2262. the tracer in C/ASM
365 * can write an offset in an unsigned 64 bit long. In java, the
366 * last bit, being set to 1 will be read as a negative number,
367 * but since it is too big a positive it will throw an
368 * exception. this will happen in 2^63 ns from 1970. Therefore
369 * 293 years from 1970
373 numValue
= Long
.parseLong(text
);
374 } catch (NumberFormatException e
) {
375 throw new ParseException("Number conversion issue with " + text
, e
); //$NON-NLS-1$
377 ctfClock
.addAttribute(key
, numValue
);
380 ctfClock
.addAttribute(key
, text
);
384 String nameValue
= ctfClock
.getName();
385 fTrace
.addClock(nameValue
, ctfClock
);
388 private void parseTrace(CommonTree traceNode
) throws ParseException
{
390 List
<CommonTree
> children
= traceNode
.getChildren();
391 if (children
== null) {
392 throw new ParseException("Trace block is empty"); //$NON-NLS-1$
397 for (CommonTree child
: children
) {
398 switch (child
.getType()) {
399 case CTFParser
.TYPEALIAS
:
400 parseTypealias(child
);
402 case CTFParser
.TYPEDEF
:
405 case CTFParser
.CTF_EXPRESSION_TYPE
:
406 case CTFParser
.CTF_EXPRESSION_VAL
:
407 parseTraceDeclaration(child
);
410 childTypeError(child
);
416 * If trace byte order was not specified and not using packet based
419 if (fTrace
.getByteOrder() == null) {
420 throw new ParseException("Trace byte order not set"); //$NON-NLS-1$
426 private void parseTraceDeclaration(CommonTree traceDecl
)
427 throws ParseException
{
429 /* There should be a left and right */
431 CommonTree leftNode
= (CommonTree
) traceDecl
.getChild(0);
432 CommonTree rightNode
= (CommonTree
) traceDecl
.getChild(1);
434 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
436 if (!isAnyUnaryString(leftStrings
.get(0))) {
437 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
440 String left
= concatenateUnaryStrings(leftStrings
);
442 if (left
.equals(MetadataStrings
.MAJOR
)) {
443 if (fTrace
.majorIsSet()) {
444 throw new ParseException("major is already set"); //$NON-NLS-1$
447 fTrace
.setMajor(getMajorOrMinor(rightNode
));
448 } else if (left
.equals(MetadataStrings
.MINOR
)) {
449 if (fTrace
.minorIsSet()) {
450 throw new ParseException("minor is already set"); //$NON-NLS-1$
453 fTrace
.setMinor(getMajorOrMinor(rightNode
));
454 } else if (left
.equals(MetadataStrings
.UUID_STRING
)) {
455 UUID uuid
= getUUID(rightNode
);
458 * If uuid was already set by a metadata packet, compare it to see
461 if (fTrace
.uuidIsSet()) {
462 if (fTrace
.getUUID().compareTo(uuid
) != 0) {
463 throw new ParseException("UUID mismatch. Packet says " //$NON-NLS-1$
464 + fTrace
.getUUID() + " but metadata says " + uuid
); //$NON-NLS-1$
467 fTrace
.setUUID(uuid
);
470 } else if (left
.equals(MetadataStrings
.BYTE_ORDER
)) {
471 ByteOrder byteOrder
= getByteOrder(rightNode
);
474 * If byte order was already set by a metadata packet, compare it to
477 if (fTrace
.getByteOrder() != null) {
478 if (fTrace
.getByteOrder() != byteOrder
) {
479 throw new ParseException(
480 "Endianness mismatch. Magic number says " //$NON-NLS-1$
481 + fTrace
.getByteOrder()
482 + " but metadata says " + byteOrder
); //$NON-NLS-1$
485 fTrace
.setByteOrder(byteOrder
);
486 final DeclarationScope parentScope
= fScope
.getParentScope();
488 for (String type
: parentScope
.getTypeNames()) {
489 IDeclaration d
= parentScope
.lookupType(type
);
490 if (d
instanceof IntegerDeclaration
) {
491 addByteOrder(byteOrder
, parentScope
, type
, (IntegerDeclaration
) d
);
492 } else if (d
instanceof StructDeclaration
) {
493 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
497 } else if (left
.equals(MetadataStrings
.PACKET_HEADER
)) {
498 if (fTrace
.packetHeaderIsSet()) {
499 throw new ParseException("packet.header already defined"); //$NON-NLS-1$
502 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
504 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
505 throw new ParseException("packet.header expects a type specifier"); //$NON-NLS-1$
508 IDeclaration packetHeaderDecl
= parseTypeSpecifierList(
509 typeSpecifier
, null);
511 if (!(packetHeaderDecl
instanceof StructDeclaration
)) {
512 throw new ParseException("packet.header expects a struct"); //$NON-NLS-1$
515 fTrace
.setPacketHeader((StructDeclaration
) packetHeaderDecl
);
517 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownTraceAttributeWarning
+ " " + left
); //$NON-NLS-1$
521 private static void addByteOrder(ByteOrder byteOrder
,
522 final DeclarationScope parentScope
, String name
,
523 IntegerDeclaration decl
) throws ParseException
{
525 if (decl
.getByteOrder() != byteOrder
) {
526 IntegerDeclaration newI
;
527 newI
= IntegerDeclaration
.createDeclaration(decl
.getLength(), decl
.isSigned(),
528 decl
.getBase(), byteOrder
, decl
.getEncoding(),
529 decl
.getClock(), decl
.getAlignment());
530 parentScope
.replaceType(name
, newI
);
534 private void setAlign(DeclarationScope parentScope
, StructDeclaration sd
,
535 ByteOrder byteOrder
) throws ParseException
{
537 for (String s
: sd
.getFieldsList()) {
538 IDeclaration d
= sd
.getField(s
);
540 if (d
instanceof StructDeclaration
) {
541 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
543 } else if (d
instanceof VariantDeclaration
) {
544 setAlign(parentScope
, (VariantDeclaration
) d
, byteOrder
);
545 } else if (d
instanceof IntegerDeclaration
) {
546 IntegerDeclaration decl
= (IntegerDeclaration
) d
;
547 if (decl
.getByteOrder() != byteOrder
) {
548 IntegerDeclaration newI
;
549 newI
= IntegerDeclaration
.createDeclaration(decl
.getLength(),
550 decl
.isSigned(), decl
.getBase(), byteOrder
,
551 decl
.getEncoding(), decl
.getClock(),
552 decl
.getAlignment());
553 sd
.getFields().put(s
, newI
);
559 private void setAlign(DeclarationScope parentScope
, VariantDeclaration vd
,
560 ByteOrder byteOrder
) throws ParseException
{
562 for (String s
: vd
.getFields().keySet()) {
563 IDeclaration d
= vd
.getFields().get(s
);
565 if (d
instanceof StructDeclaration
) {
566 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
568 } else if (d
instanceof IntegerDeclaration
) {
569 IntegerDeclaration decl
= (IntegerDeclaration
) d
;
570 IntegerDeclaration newI
;
571 newI
= IntegerDeclaration
.createDeclaration(decl
.getLength(),
572 decl
.isSigned(), decl
.getBase(), byteOrder
,
573 decl
.getEncoding(), decl
.getClock(),
574 decl
.getAlignment());
575 vd
.getFields().put(s
, newI
);
580 private void parseStream(CommonTree streamNode
) throws ParseException
{
582 CTFStream stream
= new CTFStream(fTrace
);
584 List
<CommonTree
> children
= streamNode
.getChildren();
585 if (children
== null) {
586 throw new ParseException("Empty stream block"); //$NON-NLS-1$
591 for (CommonTree child
: children
) {
592 switch (child
.getType()) {
593 case CTFParser
.TYPEALIAS
:
594 parseTypealias(child
);
596 case CTFParser
.TYPEDEF
:
599 case CTFParser
.CTF_EXPRESSION_TYPE
:
600 case CTFParser
.CTF_EXPRESSION_VAL
:
601 parseStreamDeclaration(child
, stream
);
604 childTypeError(child
);
609 if (stream
.isIdSet() &&
610 (!fTrace
.packetHeaderIsSet() || !fTrace
.getPacketHeader().hasField(MetadataStrings
.STREAM_ID
))) {
611 throw new ParseException("Stream has an ID, but there is no stream_id field in packet header."); //$NON-NLS-1$
614 fTrace
.addStream(stream
);
619 private void parseStreamDeclaration(CommonTree streamDecl
, CTFStream stream
)
620 throws ParseException
{
622 /* There should be a left and right */
624 CommonTree leftNode
= (CommonTree
) streamDecl
.getChild(0);
625 CommonTree rightNode
= (CommonTree
) streamDecl
.getChild(1);
627 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
629 if (!isAnyUnaryString(leftStrings
.get(0))) {
630 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
633 String left
= concatenateUnaryStrings(leftStrings
);
635 if (left
.equals(MetadataStrings
.ID
)) {
636 if (stream
.isIdSet()) {
637 throw new ParseException("stream id already defined"); //$NON-NLS-1$
640 long streamID
= getStreamID(rightNode
);
642 stream
.setId(streamID
);
643 } else if (left
.equals(MetadataStrings
.EVENT_HEADER
)) {
644 if (stream
.isEventHeaderSet()) {
645 throw new ParseException("event.header already defined"); //$NON-NLS-1$
648 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
650 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
651 throw new ParseException("event.header expects a type specifier"); //$NON-NLS-1$
654 IDeclaration eventHeaderDecl
= parseTypeSpecifierList(
655 typeSpecifier
, null);
657 if (eventHeaderDecl
instanceof StructDeclaration
) {
658 stream
.setEventHeader((StructDeclaration
) eventHeaderDecl
);
659 } else if (eventHeaderDecl
instanceof IEventHeaderDeclaration
) {
660 stream
.setEventHeader((IEventHeaderDeclaration
) eventHeaderDecl
);
662 throw new ParseException("event.header expects a struct"); //$NON-NLS-1$
665 } else if (left
.equals(MetadataStrings
.EVENT_CONTEXT
)) {
666 if (stream
.isEventContextSet()) {
667 throw new ParseException("event.context already defined"); //$NON-NLS-1$
670 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
672 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
673 throw new ParseException("event.context expects a type specifier"); //$NON-NLS-1$
676 IDeclaration eventContextDecl
= parseTypeSpecifierList(
677 typeSpecifier
, null);
679 if (!(eventContextDecl
instanceof StructDeclaration
)) {
680 throw new ParseException("event.context expects a struct"); //$NON-NLS-1$
683 stream
.setEventContext((StructDeclaration
) eventContextDecl
);
684 } else if (left
.equals(MetadataStrings
.PACKET_CONTEXT
)) {
685 if (stream
.isPacketContextSet()) {
686 throw new ParseException("packet.context already defined"); //$NON-NLS-1$
689 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
691 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
692 throw new ParseException("packet.context expects a type specifier"); //$NON-NLS-1$
695 IDeclaration packetContextDecl
= parseTypeSpecifierList(
696 typeSpecifier
, null);
698 if (!(packetContextDecl
instanceof StructDeclaration
)) {
699 throw new ParseException("packet.context expects a struct"); //$NON-NLS-1$
702 stream
.setPacketContext((StructDeclaration
) packetContextDecl
);
704 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownStreamAttributeWarning
+ " " + left
); //$NON-NLS-1$
708 private void parseEvent(CommonTree eventNode
) throws ParseException
{
710 List
<CommonTree
> children
= eventNode
.getChildren();
711 if (children
== null) {
712 throw new ParseException("Empty event block"); //$NON-NLS-1$
715 EventDeclaration event
= new EventDeclaration();
719 for (CommonTree child
: children
) {
720 switch (child
.getType()) {
721 case CTFParser
.TYPEALIAS
:
722 parseTypealias(child
);
724 case CTFParser
.TYPEDEF
:
727 case CTFParser
.CTF_EXPRESSION_TYPE
:
728 case CTFParser
.CTF_EXPRESSION_VAL
:
729 parseEventDeclaration(child
, event
);
732 childTypeError(child
);
737 if (!event
.nameIsSet()) {
738 throw new ParseException("Event name not set"); //$NON-NLS-1$
742 * If the event did not specify a stream, then the trace must be single
745 if (!event
.streamIsSet()) {
746 if (fTrace
.nbStreams() > 1) {
747 throw new ParseException("Event without stream_id with more than one stream"); //$NON-NLS-1$
751 * If the event did not specify a stream, the only existing stream
752 * must not have an id. Note: That behavior could be changed, it
753 * could be possible to just get the only existing stream, whatever
756 CTFStream stream
= fTrace
.getStream(null);
758 if (stream
!= null) {
759 event
.setStream(stream
);
761 throw new ParseException("Event without stream_id, but there is no stream without id"); //$NON-NLS-1$
766 * Add the event to the stream.
768 event
.getStream().addEvent(event
);
773 private void parseEventDeclaration(CommonTree eventDecl
,
774 EventDeclaration event
) throws ParseException
{
776 /* There should be a left and right */
778 CommonTree leftNode
= (CommonTree
) eventDecl
.getChild(0);
779 CommonTree rightNode
= (CommonTree
) eventDecl
.getChild(1);
781 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
783 if (!isAnyUnaryString(leftStrings
.get(0))) {
784 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
787 String left
= concatenateUnaryStrings(leftStrings
);
789 if (left
.equals(MetadataStrings
.NAME2
)) {
790 if (event
.nameIsSet()) {
791 throw new ParseException("name already defined"); //$NON-NLS-1$
794 String name
= getEventName(rightNode
);
797 } else if (left
.equals(MetadataStrings
.ID
)) {
798 if (event
.idIsSet()) {
799 throw new ParseException("id already defined"); //$NON-NLS-1$
802 long id
= getEventID(rightNode
);
803 if (id
> Integer
.MAX_VALUE
) {
804 throw new ParseException("id is greater than int.maxvalue, unsupported. id : " + id
); //$NON-NLS-1$
807 throw new ParseException("negative id, unsupported. id : " + id
); //$NON-NLS-1$
809 event
.setId((int) id
);
810 } else if (left
.equals(MetadataStrings
.STREAM_ID
)) {
811 if (event
.streamIsSet()) {
812 throw new ParseException("stream id already defined"); //$NON-NLS-1$
815 long streamId
= getStreamID(rightNode
);
817 CTFStream stream
= fTrace
.getStream(streamId
);
819 if (stream
== null) {
820 throw new ParseException("Stream " + streamId
+ " not found"); //$NON-NLS-1$ //$NON-NLS-2$
823 event
.setStream(stream
);
824 } else if (left
.equals(MetadataStrings
.CONTEXT
)) {
825 if (event
.contextIsSet()) {
826 throw new ParseException("context already defined"); //$NON-NLS-1$
829 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
831 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
832 throw new ParseException("context expects a type specifier"); //$NON-NLS-1$
835 IDeclaration contextDecl
= parseTypeSpecifierList(typeSpecifier
,
838 if (!(contextDecl
instanceof StructDeclaration
)) {
839 throw new ParseException("context expects a struct"); //$NON-NLS-1$
842 event
.setContext((StructDeclaration
) contextDecl
);
843 } else if (left
.equals(MetadataStrings
.FIELDS_STRING
)) {
844 if (event
.fieldsIsSet()) {
845 throw new ParseException("fields already defined"); //$NON-NLS-1$
848 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
850 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
851 throw new ParseException("fields expects a type specifier"); //$NON-NLS-1$
854 IDeclaration fieldsDecl
;
855 fieldsDecl
= parseTypeSpecifierList(typeSpecifier
, null);
857 if (!(fieldsDecl
instanceof StructDeclaration
)) {
858 throw new ParseException("fields expects a struct"); //$NON-NLS-1$
861 * The underscores in the event names. These underscores were added
862 * by the LTTng tracer.
864 final StructDeclaration fields
= (StructDeclaration
) fieldsDecl
;
865 event
.setFields(fields
);
866 } else if (left
.equals(MetadataStrings
.LOGLEVEL2
)) {
867 long logLevel
= parseUnaryInteger((CommonTree
) rightNode
.getChild(0));
868 event
.setLogLevel(logLevel
);
870 /* Custom event attribute, we'll add it to the attributes map */
871 String right
= parseUnaryString((CommonTree
) rightNode
.getChild(0));
872 event
.setCustomAttribute(left
, right
);
877 * Parses a declaration at the root level.
880 * The declaration subtree.
881 * @throws ParseException
883 private void parseRootDeclaration(CommonTree declaration
)
884 throws ParseException
{
886 List
<CommonTree
> children
= declaration
.getChildren();
888 for (CommonTree child
: children
) {
889 switch (child
.getType()) {
890 case CTFParser
.TYPEDEF
:
893 case CTFParser
.TYPEALIAS
:
894 parseTypealias(child
);
896 case CTFParser
.TYPE_SPECIFIER_LIST
:
897 parseTypeSpecifierList(child
, null);
900 childTypeError(child
);
906 * Parses a typealias node. It parses the target, the alias, and registers
907 * the type in the current scope.
911 * @throws ParseException
913 private void parseTypealias(CommonTree typealias
) throws ParseException
{
915 List
<CommonTree
> children
= typealias
.getChildren();
917 CommonTree target
= null;
918 CommonTree alias
= null;
920 for (CommonTree child
: children
) {
921 switch (child
.getType()) {
922 case CTFParser
.TYPEALIAS_TARGET
:
925 case CTFParser
.TYPEALIAS_ALIAS
:
929 childTypeError(child
);
934 IDeclaration targetDeclaration
= parseTypealiasTarget(target
);
936 if ((targetDeclaration
instanceof VariantDeclaration
)
937 && ((VariantDeclaration
) targetDeclaration
).isTagged()) {
938 throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
941 String aliasString
= parseTypealiasAlias(alias
);
943 getCurrentScope().registerType(aliasString
, targetDeclaration
);
947 * Parses the target part of a typealias and gets the corresponding
951 * A TYPEALIAS_TARGET node.
952 * @return The corresponding declaration.
953 * @throws ParseException
955 private IDeclaration
parseTypealiasTarget(CommonTree target
)
956 throws ParseException
{
958 List
<CommonTree
> children
= target
.getChildren();
960 CommonTree typeSpecifierList
= null;
961 CommonTree typeDeclaratorList
= null;
962 CommonTree typeDeclarator
= null;
963 StringBuilder identifierSB
= new StringBuilder();
965 for (CommonTree child
: children
) {
966 switch (child
.getType()) {
967 case CTFParser
.TYPE_SPECIFIER_LIST
:
968 typeSpecifierList
= child
;
970 case CTFParser
.TYPE_DECLARATOR_LIST
:
971 typeDeclaratorList
= child
;
974 childTypeError(child
);
979 if (typeDeclaratorList
!= null) {
981 * Only allow one declarator
983 * eg: "typealias uint8_t *, ** := puint8_t;" is not permitted,
984 * otherwise the new type puint8_t would maps to two different
987 if (typeDeclaratorList
.getChildCount() != 1) {
988 throw new ParseException("Only one type declarator is allowed in the typealias target"); //$NON-NLS-1$
991 typeDeclarator
= (CommonTree
) typeDeclaratorList
.getChild(0);
994 /* Parse the target type and get the declaration */
995 IDeclaration targetDeclaration
= parseTypeDeclarator(typeDeclarator
,
996 typeSpecifierList
, identifierSB
);
999 * We don't allow identifier in the target
1001 * eg: "typealias uint8_t* hello := puint8_t;", the "hello" is not
1004 if (identifierSB
.length() > 0) {
1005 throw new ParseException("Identifier (" + identifierSB
.toString() //$NON-NLS-1$
1006 + ") not expected in the typealias target"); //$NON-NLS-1$
1009 return targetDeclaration
;
1013 * Parses the alias part of a typealias. It parses the underlying specifier
1014 * list and declarator and creates the string representation that will be
1015 * used to register the type.
1018 * A TYPEALIAS_ALIAS node.
1019 * @return The string representation of the alias.
1020 * @throws ParseException
1022 private static String
parseTypealiasAlias(CommonTree alias
)
1023 throws ParseException
{
1025 List
<CommonTree
> children
= alias
.getChildren();
1027 CommonTree typeSpecifierList
= null;
1028 CommonTree typeDeclaratorList
= null;
1029 CommonTree typeDeclarator
= null;
1030 List
<CommonTree
> pointers
= new LinkedList
<>();
1032 for (CommonTree child
: children
) {
1033 switch (child
.getType()) {
1034 case CTFParser
.TYPE_SPECIFIER_LIST
:
1035 typeSpecifierList
= child
;
1037 case CTFParser
.TYPE_DECLARATOR_LIST
:
1038 typeDeclaratorList
= child
;
1041 childTypeError(child
);
1046 /* If there is a type declarator list, extract the pointers */
1047 if (typeDeclaratorList
!= null) {
1049 * Only allow one declarator
1051 * eg: "typealias uint8_t := puint8_t *, **;" is not permitted.
1053 if (typeDeclaratorList
.getChildCount() != 1) {
1054 throw new ParseException("Only one type declarator is allowed in the typealias alias"); //$NON-NLS-1$
1057 typeDeclarator
= (CommonTree
) typeDeclaratorList
.getChild(0);
1059 List
<CommonTree
> typeDeclaratorChildren
= typeDeclarator
.getChildren();
1061 for (CommonTree child
: typeDeclaratorChildren
) {
1062 switch (child
.getType()) {
1063 case CTFParser
.POINTER
:
1064 pointers
.add(child
);
1066 case CTFParser
.IDENTIFIER
:
1067 throw new ParseException("Identifier (" + child
.getText() //$NON-NLS-1$
1068 + ") not expected in the typealias target"); //$NON-NLS-1$
1070 childTypeError(child
);
1076 return createTypeDeclarationString(typeSpecifierList
, pointers
);
1080 * Parses a typedef node. This creates and registers a new declaration for
1081 * each declarator found in the typedef.
1085 * @throws ParseException
1086 * If there is an error creating the declaration.
1088 private void parseTypedef(CommonTree typedef
) throws ParseException
{
1090 CommonTree typeDeclaratorListNode
= (CommonTree
) typedef
.getFirstChildWithType(CTFParser
.TYPE_DECLARATOR_LIST
);
1092 CommonTree typeSpecifierListNode
= (CommonTree
) typedef
.getFirstChildWithType(CTFParser
.TYPE_SPECIFIER_LIST
);
1094 List
<CommonTree
> typeDeclaratorList
= typeDeclaratorListNode
.getChildren();
1096 for (CommonTree typeDeclaratorNode
: typeDeclaratorList
) {
1097 StringBuilder identifierSB
= new StringBuilder();
1099 IDeclaration typeDeclaration
= parseTypeDeclarator(
1100 typeDeclaratorNode
, typeSpecifierListNode
, identifierSB
);
1102 if ((typeDeclaration
instanceof VariantDeclaration
)
1103 && ((VariantDeclaration
) typeDeclaration
).isTagged()) {
1104 throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
1107 getCurrentScope().registerType(identifierSB
.toString(),
1113 * Parses a pair type declarator / type specifier list and returns the
1114 * corresponding declaration. If it is present, it also writes the
1115 * identifier of the declarator in the given {@link StringBuilder}.
1117 * @param typeDeclarator
1118 * A TYPE_DECLARATOR node.
1119 * @param typeSpecifierList
1120 * A TYPE_SPECIFIER_LIST node.
1121 * @param identifierSB
1122 * A StringBuilder that will receive the identifier found in the
1124 * @return The corresponding declaration.
1125 * @throws ParseException
1126 * If there is an error finding or creating the declaration.
1128 private IDeclaration
parseTypeDeclarator(CommonTree typeDeclarator
,
1129 CommonTree typeSpecifierList
, StringBuilder identifierSB
)
1130 throws ParseException
{
1132 IDeclaration declaration
= null;
1133 List
<CommonTree
> children
= null;
1134 List
<CommonTree
> pointers
= new LinkedList
<>();
1135 List
<CommonTree
> lengths
= new LinkedList
<>();
1136 CommonTree identifier
= null;
1138 /* Separate the tokens by type */
1139 if (typeDeclarator
!= null) {
1140 children
= typeDeclarator
.getChildren();
1141 for (CommonTree child
: children
) {
1143 switch (child
.getType()) {
1144 case CTFParser
.POINTER
:
1145 pointers
.add(child
);
1147 case CTFParser
.IDENTIFIER
:
1150 case CTFParser
.LENGTH
:
1154 childTypeError(child
);
1162 * Parse the type specifier list, which is the "base" type. For example,
1163 * it would be int in int a[3][len].
1165 declaration
= parseTypeSpecifierList(typeSpecifierList
, pointers
);
1168 * Each length subscript means that we must create a nested array or
1169 * sequence. For example, int a[3][len] means that we have an array of 3
1170 * (sequences of length 'len' of (int)).
1172 if (!lengths
.isEmpty()) {
1173 /* We begin at the end */
1174 Collections
.reverse(lengths
);
1176 for (CommonTree length
: lengths
) {
1178 * By looking at the first expression, we can determine whether
1179 * it is an array or a sequence.
1181 List
<CommonTree
> lengthChildren
= length
.getChildren();
1183 CommonTree first
= lengthChildren
.get(0);
1184 if (isUnaryInteger(first
)) {
1186 int arrayLength
= (int) parseUnaryInteger(first
);
1188 if (arrayLength
< 1) {
1189 throw new ParseException("Array length is negative"); //$NON-NLS-1$
1192 /* Create the array declaration. */
1193 declaration
= new ArrayDeclaration(arrayLength
, declaration
);
1194 } else if (isAnyUnaryString(first
)) {
1196 String lengthName
= concatenateUnaryStrings(lengthChildren
);
1198 /* check that lengthName was declared */
1199 if (isSignedIntegerField(lengthName
)) {
1200 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
1202 /* Create the sequence declaration. */
1203 declaration
= new SequenceDeclaration(lengthName
,
1206 childTypeError(first
);
1211 if (identifier
!= null) {
1212 identifierSB
.append(identifier
.getText());
1218 private boolean isSignedIntegerField(String lengthName
) throws ParseException
{
1219 IDeclaration decl
= getCurrentScope().lookupIdentifierRecursive(lengthName
);
1220 if (decl
instanceof IntegerDeclaration
) {
1221 return ((IntegerDeclaration
) decl
).isSigned();
1223 throw new ParseException("Is not an integer: " + lengthName
); //$NON-NLS-1$
1228 * Parses a type specifier list and returns the corresponding declaration.
1230 * @param typeSpecifierList
1231 * A TYPE_SPECIFIER_LIST node.
1232 * @param pointerList
1233 * A list of POINTER nodes that apply to the specified type.
1234 * @return The corresponding declaration.
1235 * @throws ParseException
1236 * If the type has not been defined or if there is an error
1237 * creating the declaration.
1239 private IDeclaration
parseTypeSpecifierList(CommonTree typeSpecifierList
,
1240 List
<CommonTree
> pointerList
) throws ParseException
{
1241 IDeclaration declaration
= null;
1244 * By looking at the first element of the type specifier list, we can
1245 * determine which type it belongs to.
1247 CommonTree firstChild
= (CommonTree
) typeSpecifierList
.getChild(0);
1249 switch (firstChild
.getType()) {
1250 case CTFParser
.FLOATING_POINT
:
1251 declaration
= parseFloat(firstChild
);
1253 case CTFParser
.INTEGER
:
1254 declaration
= parseInteger(firstChild
);
1256 case CTFParser
.STRING
:
1257 declaration
= parseString(firstChild
);
1259 case CTFParser
.STRUCT
:
1260 declaration
= parseStruct(firstChild
);
1261 StructDeclaration structDeclaration
= (StructDeclaration
) declaration
;
1262 IDeclaration idEnumDecl
= structDeclaration
.getFields().get("id"); //$NON-NLS-1$
1263 if (EventHeaderCompactDeclaration
.isCompactEventHeader(structDeclaration
)) {
1264 ByteOrder bo
= ((EnumDeclaration
) idEnumDecl
).getContainerType().getByteOrder();
1265 declaration
= EventHeaderCompactDeclaration
.getEventHeader(bo
);
1266 } else if (EventHeaderLargeDeclaration
.isLargeEventHeader(structDeclaration
)) {
1267 ByteOrder bo
= ((EnumDeclaration
) idEnumDecl
).getContainerType().getByteOrder();
1268 declaration
= EventHeaderLargeDeclaration
.getEventHeader(bo
);
1271 case CTFParser
.VARIANT
:
1272 declaration
= parseVariant(firstChild
);
1274 case CTFParser
.ENUM
:
1275 declaration
= parseEnum(firstChild
);
1277 case CTFParser
.IDENTIFIER
:
1278 case CTFParser
.FLOATTOK
:
1279 case CTFParser
.INTTOK
:
1280 case CTFParser
.LONGTOK
:
1281 case CTFParser
.SHORTTOK
:
1282 case CTFParser
.SIGNEDTOK
:
1283 case CTFParser
.UNSIGNEDTOK
:
1284 case CTFParser
.CHARTOK
:
1285 case CTFParser
.DOUBLETOK
:
1286 case CTFParser
.VOIDTOK
:
1287 case CTFParser
.BOOLTOK
:
1288 case CTFParser
.COMPLEXTOK
:
1289 case CTFParser
.IMAGINARYTOK
:
1290 declaration
= parseTypeDeclaration(typeSpecifierList
, pointerList
);
1293 childTypeError(firstChild
);
1299 private IDeclaration
parseFloat(CommonTree floatingPoint
)
1300 throws ParseException
{
1302 List
<CommonTree
> children
= floatingPoint
.getChildren();
1305 * If the integer has no attributes, then it is missing the size
1306 * attribute which is required
1308 if (children
== null) {
1309 throw new ParseException("float: missing size attribute"); //$NON-NLS-1$
1312 /* The return value */
1313 FloatDeclaration floatDeclaration
= null;
1314 ByteOrder byteOrder
= fTrace
.getByteOrder();
1317 int exponent
= DEFAULT_FLOAT_EXPONENT
;
1318 int mantissa
= DEFAULT_FLOAT_MANTISSA
;
1320 /* Iterate on all integer children */
1321 for (CommonTree child
: children
) {
1322 switch (child
.getType()) {
1323 case CTFParser
.CTF_EXPRESSION_VAL
:
1325 * An assignment expression must have 2 children, left and right
1328 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1329 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1331 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1333 if (!isAnyUnaryString(leftStrings
.get(0))) {
1334 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1336 String left
= concatenateUnaryStrings(leftStrings
);
1338 if (left
.equals(MetadataStrings
.EXP_DIG
)) {
1339 exponent
= (int) parseUnaryInteger((CommonTree
) rightNode
.getChild(0));
1340 } else if (left
.equals(MetadataStrings
.BYTE_ORDER
)) {
1341 byteOrder
= getByteOrder(rightNode
);
1342 } else if (left
.equals(MetadataStrings
.MANT_DIG
)) {
1343 mantissa
= (int) parseUnaryInteger((CommonTree
) rightNode
.getChild(0));
1344 } else if (left
.equals(MetadataStrings
.ALIGN
)) {
1345 alignment
= getAlignment(rightNode
);
1347 throw new ParseException("Float: unknown attribute " + left
); //$NON-NLS-1$
1352 childTypeError(child
);
1356 int size
= mantissa
+ exponent
;
1358 throw new ParseException("Float missing size attribute"); //$NON-NLS-1$
1361 if (alignment
== 0) {
1362 alignment
= ((size
% DEFAULT_ALIGNMENT
) == 0) ?
1 : DEFAULT_ALIGNMENT
;
1365 floatDeclaration
= new FloatDeclaration(exponent
, mantissa
, byteOrder
, alignment
);
1367 return floatDeclaration
;
1372 * Parses a type specifier list as a user-declared type.
1374 * @param typeSpecifierList
1375 * A TYPE_SPECIFIER_LIST node containing a user-declared type.
1376 * @param pointerList
1377 * A list of POINTER nodes that apply to the type specified in
1378 * typeSpecifierList.
1379 * @return The corresponding declaration.
1380 * @throws ParseException
1381 * If the type does not exist (has not been found).
1383 private IDeclaration
parseTypeDeclaration(CommonTree typeSpecifierList
,
1384 List
<CommonTree
> pointerList
) throws ParseException
{
1385 /* Create the string representation of the type declaration */
1386 String typeStringRepresentation
= createTypeDeclarationString(
1387 typeSpecifierList
, pointerList
);
1389 /* Use the string representation to search the type in the current scope */
1390 IDeclaration decl
= getCurrentScope().lookupTypeRecursive(
1391 typeStringRepresentation
);
1394 throw new ParseException("Type " + typeStringRepresentation
//$NON-NLS-1$
1395 + " has not been defined."); //$NON-NLS-1$
1402 * Parses an integer declaration node.
1406 * @return The corresponding integer declaration.
1407 * @throws ParseException
1409 private IntegerDeclaration
parseInteger(CommonTree integer
)
1410 throws ParseException
{
1412 List
<CommonTree
> children
= integer
.getChildren();
1415 * If the integer has no attributes, then it is missing the size
1416 * attribute which is required
1418 if (children
== null) {
1419 throw new ParseException("integer: missing size attribute"); //$NON-NLS-1$
1422 /* The return value */
1423 IntegerDeclaration integerDeclaration
= null;
1424 boolean signed
= false;
1425 ByteOrder byteOrder
= fTrace
.getByteOrder();
1428 int base
= DEFAULT_INT_BASE
;
1430 String clock
= EMPTY_STRING
;
1432 Encoding encoding
= Encoding
.NONE
;
1434 /* Iterate on all integer children */
1435 for (CommonTree child
: children
) {
1436 switch (child
.getType()) {
1437 case CTFParser
.CTF_EXPRESSION_VAL
:
1439 * An assignment expression must have 2 children, left and right
1442 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1443 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1445 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1447 if (!isAnyUnaryString(leftStrings
.get(0))) {
1448 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1450 String left
= concatenateUnaryStrings(leftStrings
);
1452 if (left
.equals(SIGNED
)) {
1453 signed
= getSigned(rightNode
);
1454 } else if (left
.equals(MetadataStrings
.BYTE_ORDER
)) {
1455 byteOrder
= getByteOrder(rightNode
);
1456 } else if (left
.equals(SIZE
)) {
1457 size
= getSize(rightNode
);
1458 } else if (left
.equals(MetadataStrings
.ALIGN
)) {
1459 alignment
= getAlignment(rightNode
);
1460 } else if (left
.equals(BASE
)) {
1461 base
= getBase(rightNode
);
1462 } else if (left
.equals(ENCODING
)) {
1463 encoding
= getEncoding(rightNode
);
1464 } else if (left
.equals(MAP
)) {
1465 clock
= getClock(rightNode
);
1467 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownIntegerAttributeWarning
+ " " + left
); //$NON-NLS-1$
1472 childTypeError(child
);
1478 throw new ParseException("Integer missing size attribute"); //$NON-NLS-1$
1481 if (alignment
== 0) {
1482 alignment
= ((size
% DEFAULT_ALIGNMENT
) == 0) ?
1 : DEFAULT_ALIGNMENT
;
1485 integerDeclaration
= IntegerDeclaration
.createDeclaration((int) size
, signed
, base
,
1486 byteOrder
, encoding
, clock
, alignment
);
1488 return integerDeclaration
;
1492 private static String
getClock(CommonTree rightNode
) {
1493 String clock
= rightNode
.getChild(1).getChild(0).getChild(0).getText();
1494 return clock
== null ? EMPTY_STRING
: clock
;
1497 private static StringDeclaration
parseString(CommonTree string
)
1498 throws ParseException
{
1500 List
<CommonTree
> children
= string
.getChildren();
1501 StringDeclaration stringDeclaration
= null;
1503 if (children
== null) {
1504 stringDeclaration
= new StringDeclaration();
1506 Encoding encoding
= Encoding
.UTF8
;
1507 for (CommonTree child
: children
) {
1508 switch (child
.getType()) {
1509 case CTFParser
.CTF_EXPRESSION_VAL
:
1511 * An assignment expression must have 2 children, left and
1515 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1516 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1518 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1520 if (!isAnyUnaryString(leftStrings
.get(0))) {
1521 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1523 String left
= concatenateUnaryStrings(leftStrings
);
1525 if (left
.equals(ENCODING
)) {
1526 encoding
= getEncoding(rightNode
);
1528 throw new ParseException("String: unknown attribute " //$NON-NLS-1$
1534 childTypeError(child
);
1539 stringDeclaration
= new StringDeclaration(encoding
);
1542 return stringDeclaration
;
1546 * Parses a struct declaration and returns the corresponding declaration.
1550 * @return The corresponding struct declaration.
1551 * @throws ParseException
1553 private StructDeclaration
parseStruct(CommonTree struct
)
1554 throws ParseException
{
1556 List
<CommonTree
> children
= struct
.getChildren();
1558 /* The return value */
1559 StructDeclaration structDeclaration
= null;
1562 String structName
= null;
1563 boolean hasName
= false;
1566 CommonTree structBody
= null;
1567 boolean hasBody
= false;
1570 long structAlign
= 0;
1572 /* Loop on all children and identify what we have to work with. */
1573 for (CommonTree child
: children
) {
1574 switch (child
.getType()) {
1575 case CTFParser
.STRUCT_NAME
: {
1578 CommonTree structNameIdentifier
= (CommonTree
) child
.getChild(0);
1580 structName
= structNameIdentifier
.getText();
1584 case CTFParser
.STRUCT_BODY
: {
1591 case CTFParser
.ALIGN
: {
1592 CommonTree structAlignExpression
= (CommonTree
) child
.getChild(0);
1594 structAlign
= getAlignment(structAlignExpression
);
1599 childTypeError(child
);
1606 * If a struct has just a body and no name (just like the song,
1607 * "A Struct With No Name" by America (sorry for that...)), it's a
1608 * definition of a new type, so we create the type declaration and
1609 * return it. We can't add it to the declaration scope since there is no
1610 * name, but that's what we want because it won't be possible to use it
1611 * again to declare another field.
1613 * If it has just a name, we look it up in the declaration scope and
1614 * return the associated declaration. If it is not found in the
1615 * declaration scope, it means that a struct with that name has not been
1616 * declared, which is an error.
1618 * If it has both, then we create the type declaration and register it
1619 * to the current scope.
1621 * If it has none, then what are we doing here ?
1625 * If struct has a name, check if already defined in the current
1628 if (hasName
&& (getCurrentScope().lookupStruct(structName
) != null)) {
1629 throw new ParseException("struct " + structName
//$NON-NLS-1$
1630 + " already defined."); //$NON-NLS-1$
1632 /* Create the declaration */
1633 structDeclaration
= new StructDeclaration(structAlign
);
1635 /* Parse the body */
1636 parseStructBody(structBody
, structDeclaration
);
1638 /* If struct has name, add it to the current scope. */
1640 getCurrentScope().registerStruct(structName
, structDeclaration
);
1642 } else /* !hasBody */{
1644 /* Name and !body */
1646 /* Lookup the name in the current scope. */
1647 structDeclaration
= getCurrentScope().lookupStructRecursive(structName
);
1650 * If not found, it means that a struct with such name has not
1653 if (structDeclaration
== null) {
1654 throw new ParseException("struct " + structName
//$NON-NLS-1$
1655 + " is not defined"); //$NON-NLS-1$
1658 /* !Name and !body */
1660 /* We can't do anything with that. */
1661 throw new ParseException("struct with no name and no body"); //$NON-NLS-1$
1664 return StructDeclarationFlattener
.tryFlattenStruct(structDeclaration
);
1668 * Parses a struct body, adding the fields to specified structure
1672 * A STRUCT_BODY node.
1673 * @param structDeclaration
1674 * The struct declaration.
1675 * @throws ParseException
1677 private void parseStructBody(CommonTree structBody
,
1678 StructDeclaration structDeclaration
) throws ParseException
{
1680 List
<CommonTree
> structDeclarations
= structBody
.getChildren();
1683 * If structDeclaration is null, structBody has no children and the
1684 * struct body is empty.
1686 if (structDeclarations
!= null) {
1689 for (CommonTree declarationNode
: structDeclarations
) {
1690 switch (declarationNode
.getType()) {
1691 case CTFParser
.TYPEALIAS
:
1692 parseTypealias(declarationNode
);
1694 case CTFParser
.TYPEDEF
:
1695 parseTypedef(declarationNode
);
1697 case CTFParser
.SV_DECLARATION
:
1698 parseStructDeclaration(declarationNode
, structDeclaration
);
1701 childTypeError(declarationNode
);
1710 * Parses a declaration found in a struct.
1712 * @param declaration
1713 * A SV_DECLARATION node.
1715 * A struct declaration. (I know, little name clash here...)
1716 * @throws ParseException
1718 private void parseStructDeclaration(CommonTree declaration
,
1719 StructDeclaration struct
) throws ParseException
{
1721 /* Get the type specifier list node */
1722 CommonTree typeSpecifierListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_SPECIFIER_LIST
);
1724 /* Get the type declarator list node */
1725 CommonTree typeDeclaratorListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_DECLARATOR_LIST
);
1727 /* Get the type declarator list */
1728 List
<CommonTree
> typeDeclaratorList
= typeDeclaratorListNode
.getChildren();
1731 * For each type declarator, parse the declaration and add a field to
1734 for (CommonTree typeDeclaratorNode
: typeDeclaratorList
) {
1736 StringBuilder identifierSB
= new StringBuilder();
1738 IDeclaration decl
= parseTypeDeclarator(typeDeclaratorNode
,
1739 typeSpecifierListNode
, identifierSB
);
1740 String fieldName
= identifierSB
.toString();
1741 getCurrentScope().registerIdentifier(fieldName
, decl
);
1743 if (struct
.hasField(fieldName
)) {
1744 throw new ParseException("struct: duplicate field " //$NON-NLS-1$
1748 struct
.addField(fieldName
, decl
);
1754 * Parses an enum declaration and returns the corresponding declaration.
1758 * @return The corresponding enum declaration.
1759 * @throws ParseException
1761 private EnumDeclaration
parseEnum(CommonTree theEnum
) throws ParseException
{
1763 List
<CommonTree
> children
= theEnum
.getChildren();
1765 /* The return value */
1766 EnumDeclaration enumDeclaration
= null;
1769 String enumName
= null;
1772 CommonTree enumBody
= null;
1774 /* Container type */
1775 IntegerDeclaration containerTypeDeclaration
= null;
1777 /* Loop on all children and identify what we have to work with. */
1778 for (CommonTree child
: children
) {
1779 switch (child
.getType()) {
1780 case CTFParser
.ENUM_NAME
: {
1781 CommonTree enumNameIdentifier
= (CommonTree
) child
.getChild(0);
1782 enumName
= enumNameIdentifier
.getText();
1785 case CTFParser
.ENUM_BODY
: {
1789 case CTFParser
.ENUM_CONTAINER_TYPE
: {
1790 containerTypeDeclaration
= parseEnumContainerType(child
);
1794 childTypeError(child
);
1800 * If the container type has not been defined explicitly, we assume it
1803 if (containerTypeDeclaration
== null) {
1804 IDeclaration enumDecl
;
1806 * it could be because the enum was already declared.
1808 if (enumName
!= null) {
1809 enumDecl
= getCurrentScope().lookupEnumRecursive(enumName
);
1810 if (enumDecl
!= null) {
1811 return (EnumDeclaration
) enumDecl
;
1815 IDeclaration decl
= getCurrentScope().lookupTypeRecursive("int"); //$NON-NLS-1$
1818 throw new ParseException("enum container type implicit and type int not defined"); //$NON-NLS-1$
1819 } else if (!(decl
instanceof IntegerDeclaration
)) {
1820 throw new ParseException("enum container type implicit and type int not an integer"); //$NON-NLS-1$
1823 containerTypeDeclaration
= (IntegerDeclaration
) decl
;
1827 * If it has a body, it's a new declaration, otherwise it's a reference
1828 * to an existing declaration. Same logic as struct.
1830 if (enumBody
!= null) {
1832 * If enum has a name, check if already defined in the current
1835 if ((enumName
!= null)
1836 && (getCurrentScope().lookupEnum(enumName
) != null)) {
1837 throw new ParseException("enum " + enumName
//$NON-NLS-1$
1838 + " already defined"); //$NON-NLS-1$
1841 /* Create the declaration */
1842 enumDeclaration
= new EnumDeclaration(containerTypeDeclaration
);
1844 /* Parse the body */
1845 parseEnumBody(enumBody
, enumDeclaration
);
1847 /* If the enum has name, add it to the current scope. */
1848 if (enumName
!= null) {
1849 getCurrentScope().registerEnum(enumName
, enumDeclaration
);
1852 if (enumName
!= null) {
1853 /* Name and !body */
1855 /* Lookup the name in the current scope. */
1856 enumDeclaration
= getCurrentScope().lookupEnumRecursive(enumName
);
1859 * If not found, it means that an enum with such name has not
1862 if (enumDeclaration
== null) {
1863 throw new ParseException("enum " + enumName
//$NON-NLS-1$
1864 + " is not defined"); //$NON-NLS-1$
1867 /* !Name and !body */
1868 throw new ParseException("enum with no name and no body"); //$NON-NLS-1$
1872 return enumDeclaration
;
1877 * Parses an enum body, adding the enumerators to the specified enum
1881 * An ENUM_BODY node.
1882 * @param enumDeclaration
1883 * The enum declaration.
1884 * @throws ParseException
1886 private void parseEnumBody(CommonTree enumBody
,
1887 EnumDeclaration enumDeclaration
) throws ParseException
{
1889 List
<CommonTree
> enumerators
= enumBody
.getChildren();
1890 /* enum body can't be empty (unlike struct). */
1895 * Start at -1, so that if the first enumrator has no explicit value, it
1900 for (CommonTree enumerator
: enumerators
) {
1901 lastHigh
= parseEnumEnumerator(enumerator
, enumDeclaration
,
1910 * Parses an enumerator node and adds an enumerator declaration to an
1911 * enumeration declaration.
1913 * The high value of the range of the last enumerator is needed in case the
1914 * current enumerator does not specify its value.
1917 * An ENUM_ENUMERATOR node.
1918 * @param enumDeclaration
1919 * en enumeration declaration to which will be added the
1922 * The high value of the range of the last enumerator
1923 * @return The high value of the value range of the current enumerator.
1924 * @throws ParseException
1926 private static long parseEnumEnumerator(CommonTree enumerator
,
1927 EnumDeclaration enumDeclaration
, long lastHigh
)
1928 throws ParseException
{
1930 List
<CommonTree
> children
= enumerator
.getChildren();
1932 long low
= 0, high
= 0;
1933 boolean valueSpecified
= false;
1934 String label
= null;
1936 for (CommonTree child
: children
) {
1937 if (isAnyUnaryString(child
)) {
1938 label
= parseUnaryString(child
);
1939 } else if (child
.getType() == CTFParser
.ENUM_VALUE
) {
1941 valueSpecified
= true;
1943 low
= parseUnaryInteger((CommonTree
) child
.getChild(0));
1945 } else if (child
.getType() == CTFParser
.ENUM_VALUE_RANGE
) {
1947 valueSpecified
= true;
1949 low
= parseUnaryInteger((CommonTree
) child
.getChild(0));
1950 high
= parseUnaryInteger((CommonTree
) child
.getChild(1));
1952 childTypeError(child
);
1956 if (!valueSpecified
) {
1962 throw new ParseException("enum low value greater than high value"); //$NON-NLS-1$
1965 if (!enumDeclaration
.add(low
, high
, label
)) {
1966 throw new ParseException("enum declarator values overlap."); //$NON-NLS-1$
1969 if (valueSpecified
&& (BigInteger
.valueOf(low
).compareTo(enumDeclaration
.getContainerType().getMinValue()) == -1 ||
1970 BigInteger
.valueOf(high
).compareTo(enumDeclaration
.getContainerType().getMaxValue()) == 1)) {
1971 throw new ParseException("enum value is not in range"); //$NON-NLS-1$
1978 * Parses an enum container type node and returns the corresponding integer
1981 * @param enumContainerType
1982 * An ENUM_CONTAINER_TYPE node.
1983 * @return An integer declaration corresponding to the container type.
1984 * @throws ParseException
1985 * If the type does not parse correctly or if it is not an
1988 private IntegerDeclaration
parseEnumContainerType(
1989 CommonTree enumContainerType
) throws ParseException
{
1991 /* Get the child, which should be a type specifier list */
1992 CommonTree typeSpecifierList
= (CommonTree
) enumContainerType
.getChild(0);
1994 /* Parse it and get the corresponding declaration */
1995 IDeclaration decl
= parseTypeSpecifierList(typeSpecifierList
, null);
1997 /* If is is an integer, return it, else throw an error */
1998 if (decl
instanceof IntegerDeclaration
) {
1999 return (IntegerDeclaration
) decl
;
2001 throw new ParseException("enum container type must be an integer"); //$NON-NLS-1$
2004 private VariantDeclaration
parseVariant(CommonTree variant
)
2005 throws ParseException
{
2007 List
<CommonTree
> children
= variant
.getChildren();
2008 VariantDeclaration variantDeclaration
= null;
2010 boolean hasName
= false;
2011 String variantName
= null;
2013 boolean hasBody
= false;
2014 CommonTree variantBody
= null;
2016 boolean hasTag
= false;
2017 String variantTag
= null;
2019 for (CommonTree child
: children
) {
2020 switch (child
.getType()) {
2021 case CTFParser
.VARIANT_NAME
:
2025 CommonTree variantNameIdentifier
= (CommonTree
) child
.getChild(0);
2027 variantName
= variantNameIdentifier
.getText();
2030 case CTFParser
.VARIANT_TAG
:
2034 CommonTree variantTagIdentifier
= (CommonTree
) child
.getChild(0);
2036 variantTag
= variantTagIdentifier
.getText();
2039 case CTFParser
.VARIANT_BODY
:
2043 variantBody
= child
;
2047 childTypeError(child
);
2054 * If variant has a name, check if already defined in the current
2058 && (getCurrentScope().lookupVariant(variantName
) != null)) {
2059 throw new ParseException("variant " + variantName
//$NON-NLS-1$
2060 + " already defined."); //$NON-NLS-1$
2063 /* Create the declaration */
2064 variantDeclaration
= new VariantDeclaration();
2066 /* Parse the body */
2067 parseVariantBody(variantBody
, variantDeclaration
);
2069 /* If variant has name, add it to the current scope. */
2071 getCurrentScope().registerVariant(variantName
,
2072 variantDeclaration
);
2074 } else /* !hasBody */{
2076 /* Name and !body */
2078 /* Lookup the name in the current scope. */
2079 variantDeclaration
= getCurrentScope().lookupVariantRecursive(
2083 * If not found, it means that a struct with such name has not
2086 if (variantDeclaration
== null) {
2087 throw new ParseException("variant " + variantName
//$NON-NLS-1$
2088 + " is not defined"); //$NON-NLS-1$
2091 /* !Name and !body */
2093 /* We can't do anything with that. */
2094 throw new ParseException("variant with no name and no body"); //$NON-NLS-1$
2099 variantDeclaration
.setTag(variantTag
);
2101 IDeclaration decl
= getCurrentScope().lookupIdentifierRecursive(variantTag
);
2103 throw new ParseException("Variant tag not found: " + variantTag
); //$NON-NLS-1$
2105 if (!(decl
instanceof EnumDeclaration
)) {
2106 throw new ParseException("Variant tag must be an enum: " + variantTag
); //$NON-NLS-1$
2108 EnumDeclaration tagDecl
= (EnumDeclaration
) decl
;
2109 Set
<String
> intersection
= new HashSet
<>(tagDecl
.getLabels());
2110 intersection
.retainAll(variantDeclaration
.getFields().keySet());
2111 if (intersection
.isEmpty()) {
2112 throw new ParseException("Variant contains no values of the tag, impossible to use: " + variantName
); //$NON-NLS-1$
2116 return variantDeclaration
;
2119 private void parseVariantBody(CommonTree variantBody
,
2120 VariantDeclaration variantDeclaration
) throws ParseException
{
2122 List
<CommonTree
> variantDeclarations
= variantBody
.getChildren();
2126 for (CommonTree declarationNode
: variantDeclarations
) {
2127 switch (declarationNode
.getType()) {
2128 case CTFParser
.TYPEALIAS
:
2129 parseTypealias(declarationNode
);
2131 case CTFParser
.TYPEDEF
:
2132 parseTypedef(declarationNode
);
2134 case CTFParser
.SV_DECLARATION
:
2135 parseVariantDeclaration(declarationNode
, variantDeclaration
);
2138 childTypeError(declarationNode
);
2146 private void parseVariantDeclaration(CommonTree declaration
,
2147 VariantDeclaration variant
) throws ParseException
{
2149 /* Get the type specifier list node */
2150 CommonTree typeSpecifierListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_SPECIFIER_LIST
);
2152 /* Get the type declarator list node */
2153 CommonTree typeDeclaratorListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_DECLARATOR_LIST
);
2155 /* Get the type declarator list */
2156 List
<CommonTree
> typeDeclaratorList
= typeDeclaratorListNode
.getChildren();
2159 * For each type declarator, parse the declaration and add a field to
2162 for (CommonTree typeDeclaratorNode
: typeDeclaratorList
) {
2164 StringBuilder identifierSB
= new StringBuilder();
2166 IDeclaration decl
= parseTypeDeclarator(typeDeclaratorNode
,
2167 typeSpecifierListNode
, identifierSB
);
2169 String name
= identifierSB
.toString();
2171 if (variant
.hasField(name
)) {
2172 throw new ParseException("variant: duplicate field " //$NON-NLS-1$
2176 getCurrentScope().registerIdentifier(name
, decl
);
2178 variant
.addField(name
, decl
);
2183 * Creates the string representation of a type declaration (type specifier
2186 * @param typeSpecifierList
2187 * A TYPE_SPECIFIER_LIST node.
2189 * A list of POINTER nodes.
2190 * @return The string representation.
2191 * @throws ParseException
2193 private static String
createTypeDeclarationString(
2194 CommonTree typeSpecifierList
, List
<CommonTree
> pointers
)
2195 throws ParseException
{
2196 StringBuilder sb
= new StringBuilder();
2198 createTypeSpecifierListString(typeSpecifierList
, sb
);
2199 createPointerListString(pointers
, sb
);
2201 return sb
.toString();
2205 * Creates the string representation of a list of type specifiers.
2207 * @param typeSpecifierList
2208 * A TYPE_SPECIFIER_LIST node.
2210 * A StringBuilder to which will be appended the string.
2211 * @throws ParseException
2213 private static void createTypeSpecifierListString(
2214 CommonTree typeSpecifierList
, StringBuilder sb
)
2215 throws ParseException
{
2217 List
<CommonTree
> children
= typeSpecifierList
.getChildren();
2219 boolean firstItem
= true;
2221 for (CommonTree child
: children
) {
2229 /* Append the string that represents this type specifier. */
2230 createTypeSpecifierString(child
, sb
);
2235 * Creates the string representation of a type specifier.
2237 * @param typeSpecifier
2238 * A TYPE_SPECIFIER node.
2240 * A StringBuilder to which will be appended the string.
2241 * @throws ParseException
2243 private static void createTypeSpecifierString(CommonTree typeSpecifier
,
2244 StringBuilder sb
) throws ParseException
{
2245 switch (typeSpecifier
.getType()) {
2246 case CTFParser
.FLOATTOK
:
2247 case CTFParser
.INTTOK
:
2248 case CTFParser
.LONGTOK
:
2249 case CTFParser
.SHORTTOK
:
2250 case CTFParser
.SIGNEDTOK
:
2251 case CTFParser
.UNSIGNEDTOK
:
2252 case CTFParser
.CHARTOK
:
2253 case CTFParser
.DOUBLETOK
:
2254 case CTFParser
.VOIDTOK
:
2255 case CTFParser
.BOOLTOK
:
2256 case CTFParser
.COMPLEXTOK
:
2257 case CTFParser
.IMAGINARYTOK
:
2258 case CTFParser
.CONSTTOK
:
2259 case CTFParser
.IDENTIFIER
:
2260 sb
.append(typeSpecifier
.getText());
2262 case CTFParser
.STRUCT
: {
2263 CommonTree structName
= (CommonTree
) typeSpecifier
.getFirstChildWithType(CTFParser
.STRUCT_NAME
);
2264 if (structName
== null) {
2265 throw new ParseException("nameless struct found in createTypeSpecifierString"); //$NON-NLS-1$
2268 CommonTree structNameIdentifier
= (CommonTree
) structName
.getChild(0);
2270 sb
.append(structNameIdentifier
.getText());
2273 case CTFParser
.VARIANT
: {
2274 CommonTree variantName
= (CommonTree
) typeSpecifier
.getFirstChildWithType(CTFParser
.VARIANT_NAME
);
2275 if (variantName
== null) {
2276 throw new ParseException("nameless variant found in createTypeSpecifierString"); //$NON-NLS-1$
2279 CommonTree variantNameIdentifier
= (CommonTree
) variantName
.getChild(0);
2281 sb
.append(variantNameIdentifier
.getText());
2284 case CTFParser
.ENUM
: {
2285 CommonTree enumName
= (CommonTree
) typeSpecifier
.getFirstChildWithType(CTFParser
.ENUM_NAME
);
2286 if (enumName
== null) {
2287 throw new ParseException("nameless enum found in createTypeSpecifierString"); //$NON-NLS-1$
2290 CommonTree enumNameIdentifier
= (CommonTree
) enumName
.getChild(0);
2292 sb
.append(enumNameIdentifier
.getText());
2295 case CTFParser
.FLOATING_POINT
:
2296 case CTFParser
.INTEGER
:
2297 case CTFParser
.STRING
:
2298 throw new ParseException("CTF type found in createTypeSpecifierString"); //$NON-NLS-1$
2300 childTypeError(typeSpecifier
);
2306 * Creates the string representation of a list of pointers.
2308 * @param pointerList
2309 * A list of pointer nodes. If pointerList is null, this function
2312 * A stringbuilder to which will be appended the string.
2314 private static void createPointerListString(List
<CommonTree
> pointerList
,
2316 if (pointerList
== null) {
2320 for (CommonTree pointer
: pointerList
) {
2322 sb
.append(" *"); //$NON-NLS-1$
2323 if (pointer
.getChildCount() > 0) {
2325 sb
.append(" const"); //$NON-NLS-1$
2332 * The node to check.
2333 * @return True if the given node is an unary string.
2335 private static boolean isUnaryString(CommonTree node
) {
2336 return ((node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING
));
2341 * The node to check.
2342 * @return True if the given node is any type of unary string (no quotes,
2345 private static boolean isAnyUnaryString(CommonTree node
) {
2346 return ((node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING
) || (node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING_QUOTES
));
2351 * The node to check.
2352 * @return True if the given node is an unary integer.
2354 private static boolean isUnaryInteger(CommonTree node
) {
2355 return ((node
.getType() == CTFParser
.UNARY_EXPRESSION_DEC
) ||
2356 (node
.getType() == CTFParser
.UNARY_EXPRESSION_HEX
) || (node
.getType() == CTFParser
.UNARY_EXPRESSION_OCT
));
2360 * Parses a unary string node and return the string value.
2362 * @param unaryString
2363 * The unary string node to parse (type UNARY_EXPRESSION_STRING
2364 * or UNARY_EXPRESSION_STRING_QUOTES).
2365 * @return The string value.
2368 * It would be really nice to remove the quotes earlier, such as in the
2371 private static String
parseUnaryString(CommonTree unaryString
) {
2373 CommonTree value
= (CommonTree
) unaryString
.getChild(0);
2374 String strval
= value
.getText();
2377 if (unaryString
.getType() == CTFParser
.UNARY_EXPRESSION_STRING_QUOTES
) {
2378 strval
= strval
.substring(1, strval
.length() - 1);
2385 * Parses an unary integer (dec, hex or oct).
2387 * @param unaryInteger
2388 * An unary integer node.
2389 * @return The integer value.
2390 * @throws ParseException
2391 * on an invalid integer format ("bob" for example)
2393 private static long parseUnaryInteger(CommonTree unaryInteger
) throws ParseException
{
2395 List
<CommonTree
> children
= unaryInteger
.getChildren();
2396 CommonTree value
= children
.get(0);
2397 String strval
= value
.getText();
2401 intval
= Long
.decode(strval
);
2402 } catch (NumberFormatException e
) {
2403 throw new ParseException("Invalid integer format: " + strval
, e
); //$NON-NLS-1$
2406 /* The rest of children are sign */
2407 if ((children
.size() % 2) == 0) {
2413 private static long getMajorOrMinor(CommonTree rightNode
)
2414 throws ParseException
{
2416 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2418 if (isUnaryInteger(firstChild
)) {
2419 if (rightNode
.getChildCount() > 1) {
2420 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2423 long m
= parseUnaryInteger(firstChild
);
2426 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2431 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2434 private static UUID
getUUID(CommonTree rightNode
) throws ParseException
{
2436 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2438 if (isAnyUnaryString(firstChild
)) {
2439 if (rightNode
.getChildCount() > 1) {
2440 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2443 String uuidstr
= parseUnaryString(firstChild
);
2446 return UUID
.fromString(uuidstr
);
2447 } catch (IllegalArgumentException e
) {
2448 throw new ParseException("Invalid format for UUID", e
); //$NON-NLS-1$
2451 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2455 * Gets the value of a "signed" integer attribute.
2459 * @return The "signed" value as a boolean.
2460 * @throws ParseException
2462 private static boolean getSigned(CommonTree rightNode
)
2463 throws ParseException
{
2465 boolean ret
= false;
2466 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2468 if (isUnaryString(firstChild
)) {
2469 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
2471 if (strval
.equals(MetadataStrings
.TRUE
)
2472 || strval
.equals(MetadataStrings
.TRUE2
)) {
2474 } else if (strval
.equals(MetadataStrings
.FALSE
)
2475 || strval
.equals(MetadataStrings
.FALSE2
)) {
2478 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2479 + firstChild
.getChild(0).getText());
2481 } else if (isUnaryInteger(firstChild
)) {
2482 /* Happens if the value is something like "1234.hello" */
2483 if (rightNode
.getChildCount() > 1) {
2484 throw new ParseException("Invalid boolean value"); //$NON-NLS-1$
2487 long intval
= parseUnaryInteger(firstChild
);
2491 } else if (intval
== 0) {
2494 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2495 + firstChild
.getChild(0).getText());
2498 throw new ParseException();
2505 * Gets the value of a "byte_order" integer attribute.
2509 * @return The "byte_order" value.
2510 * @throws ParseException
2512 private ByteOrder
getByteOrder(CommonTree rightNode
) throws ParseException
{
2514 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2516 if (isUnaryString(firstChild
)) {
2517 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
2519 if (strval
.equals(MetadataStrings
.LE
)) {
2520 return ByteOrder
.LITTLE_ENDIAN
;
2521 } else if (strval
.equals(MetadataStrings
.BE
)
2522 || strval
.equals(MetadataStrings
.NETWORK
)) {
2523 return ByteOrder
.BIG_ENDIAN
;
2524 } else if (strval
.equals(MetadataStrings
.NATIVE
)) {
2525 return fTrace
.getByteOrder();
2527 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2530 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2534 * Determines if the given value is a valid alignment value.
2537 * The value to check.
2538 * @return True if it is valid.
2540 private static boolean isValidAlignment(long alignment
) {
2541 return !((alignment
<= 0) || ((alignment
& (alignment
- 1)) != 0));
2545 * Gets the value of a "size" integer attribute.
2549 * @return The "size" value.
2550 * @throws ParseException
2552 private static long getSize(CommonTree rightNode
) throws ParseException
{
2554 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2556 if (isUnaryInteger(firstChild
)) {
2557 if (rightNode
.getChildCount() > 1) {
2558 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2561 long size
= parseUnaryInteger(firstChild
);
2564 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2569 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2573 * Gets the value of a "align" integer or struct attribute.
2576 * A CTF_RIGHT node or directly an unary integer.
2577 * @return The align value.
2578 * @throws ParseException
2580 private static long getAlignment(CommonTree node
) throws ParseException
{
2583 * If a CTF_RIGHT node was passed, call getAlignment with the first
2586 if (node
.getType() == CTFParser
.CTF_RIGHT
) {
2587 if (node
.getChildCount() > 1) {
2588 throw new ParseException("Invalid alignment value"); //$NON-NLS-1$
2591 return getAlignment((CommonTree
) node
.getChild(0));
2592 } else if (isUnaryInteger(node
)) {
2593 long alignment
= parseUnaryInteger(node
);
2595 if (!isValidAlignment(alignment
)) {
2596 throw new ParseException("Invalid value for alignment : " //$NON-NLS-1$
2602 throw new ParseException("Invalid value for alignment"); //$NON-NLS-1$
2606 * Gets the value of a "base" integer attribute.
2609 * An CTF_RIGHT node.
2610 * @return The "base" value.
2611 * @throws ParseException
2613 private static int getBase(CommonTree rightNode
) throws ParseException
{
2615 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2617 if (isUnaryInteger(firstChild
)) {
2618 if (rightNode
.getChildCount() > 1) {
2619 throw new ParseException("invalid base value"); //$NON-NLS-1$
2622 long intval
= parseUnaryInteger(firstChild
);
2623 if ((intval
== INTEGER_BASE_2
) || (intval
== INTEGER_BASE_8
) || (intval
== INTEGER_BASE_10
)
2624 || (intval
== INTEGER_BASE_16
)) {
2625 return (int) intval
;
2627 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2628 } else if (isUnaryString(firstChild
)) {
2629 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
2631 if (strval
.equals(MetadataStrings
.DECIMAL
)
2632 || strval
.equals(MetadataStrings
.DEC
)
2633 || strval
.equals(MetadataStrings
.DEC_CTE
)
2634 || strval
.equals(MetadataStrings
.INT_MOD
)
2635 || strval
.equals(MetadataStrings
.UNSIGNED_CTE
)) {
2636 return INTEGER_BASE_10
;
2637 } else if (strval
.equals(MetadataStrings
.HEXADECIMAL
)
2638 || strval
.equals(MetadataStrings
.HEX
)
2639 || strval
.equals(MetadataStrings
.X
)
2640 || strval
.equals(MetadataStrings
.X2
)
2641 || strval
.equals(MetadataStrings
.POINTER
)) {
2642 return INTEGER_BASE_16
;
2643 } else if (strval
.equals(MetadataStrings
.OCTAL
)
2644 || strval
.equals(MetadataStrings
.OCT
)
2645 || strval
.equals(MetadataStrings
.OCTAL_CTE
)) {
2646 return INTEGER_BASE_8
;
2647 } else if (strval
.equals(MetadataStrings
.BINARY
)
2648 || strval
.equals(MetadataStrings
.BIN
)) {
2649 return INTEGER_BASE_2
;
2651 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2654 throw new ParseException("invalid value for base"); //$NON-NLS-1$
2659 * Gets the value of an "encoding" integer attribute.
2663 * @return The "encoding" value.
2664 * @throws ParseException
2667 private static Encoding
getEncoding(CommonTree rightNode
)
2668 throws ParseException
{
2670 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2672 if (isUnaryString(firstChild
)) {
2673 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
2675 if (strval
.equals(MetadataStrings
.UTF8
)) {
2676 return Encoding
.UTF8
;
2677 } else if (strval
.equals(MetadataStrings
.ASCII
)) {
2678 return Encoding
.ASCII
;
2679 } else if (strval
.equals(MetadataStrings
.NONE
)) {
2680 return Encoding
.NONE
;
2682 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2685 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2688 private static long getStreamID(CommonTree rightNode
) throws ParseException
{
2690 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2692 if (isUnaryInteger(firstChild
)) {
2693 if (rightNode
.getChildCount() > 1) {
2694 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2697 long intval
= parseUnaryInteger(firstChild
);
2701 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2704 private static String
getEventName(CommonTree rightNode
)
2705 throws ParseException
{
2707 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2709 if (isAnyUnaryString(firstChild
)) {
2710 String str
= concatenateUnaryStrings(rightNode
.getChildren());
2714 throw new ParseException("invalid value for event name"); //$NON-NLS-1$
2717 private static long getEventID(CommonTree rightNode
) throws ParseException
{
2719 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2721 if (isUnaryInteger(firstChild
)) {
2722 if (rightNode
.getChildCount() > 1) {
2723 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2726 long intval
= parseUnaryInteger(firstChild
);
2727 if (intval
> Integer
.MAX_VALUE
) {
2728 throw new ParseException("Event id larger than int.maxvalue, something is amiss"); //$NON-NLS-1$
2732 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2736 * Concatenates a list of unary strings separated by arrows (->) or dots.
2739 * A list, first element being an unary string, subsequent
2740 * elements being ARROW or DOT nodes with unary strings as child.
2741 * @return The string representation of the unary string chain.
2743 private static String
concatenateUnaryStrings(List
<CommonTree
> strings
) {
2745 StringBuilder sb
= new StringBuilder();
2747 CommonTree first
= strings
.get(0);
2748 sb
.append(parseUnaryString(first
));
2750 boolean isFirst
= true;
2752 for (CommonTree ref
: strings
) {
2758 CommonTree id
= (CommonTree
) ref
.getChild(0);
2760 if (ref
.getType() == CTFParser
.ARROW
) {
2761 sb
.append("->"); //$NON-NLS-1$
2766 sb
.append(parseUnaryString(id
));
2769 return sb
.toString();
2773 * Throws a ParseException stating that the parent-child relation between
2774 * the given node and its parent is not valid. It means that the shape of
2775 * the AST is unexpected.
2778 * The invalid child node.
2779 * @throws ParseException
2781 private static void childTypeError(CommonTree child
) throws ParseException
{
2782 CommonTree parent
= (CommonTree
) child
.getParent();
2783 String error
= "Parent " + CTFParser
.tokenNames
[parent
.getType()] //$NON-NLS-1$
2784 + " can't have a child of type " //$NON-NLS-1$
2785 + CTFParser
.tokenNames
[child
.getType()] + "."; //$NON-NLS-1$
2787 throw new ParseException(error
);
2790 // ------------------------------------------------------------------------
2792 // ------------------------------------------------------------------------
2795 * Adds a new declaration scope on the top of the scope stack.
2797 private void pushScope() {
2798 fScope
= new DeclarationScope(fScope
);
2802 * Removes the top declaration scope from the scope stack.
2804 private void popScope() {
2805 fScope
= fScope
.getParentScope();
2809 * Returns the current declaration scope.
2811 * @return The current declaration scope.
2813 private DeclarationScope
getCurrentScope() {