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
;
52 import com
.google
.common
.collect
.Iterables
;
57 public class IOStructGen
{
59 // ------------------------------------------------------------------------
61 // ------------------------------------------------------------------------
63 private static final @NonNull String MAP
= "map"; //$NON-NLS-1$
64 private static final @NonNull String ENCODING
= "encoding"; //$NON-NLS-1$
65 private static final @NonNull String BASE
= "base"; //$NON-NLS-1$
66 private static final @NonNull String SIZE
= "size"; //$NON-NLS-1$
67 private static final @NonNull String SIGNED
= "signed"; //$NON-NLS-1$
68 private static final @NonNull String LINE
= "line"; //$NON-NLS-1$
69 private static final @NonNull String FILE
= "file"; //$NON-NLS-1$
70 private static final @NonNull String IP
= "ip"; //$NON-NLS-1$
71 private static final @NonNull String FUNC
= "func"; //$NON-NLS-1$
72 private static final @NonNull String NAME
= "name"; //$NON-NLS-1$
73 private static final @NonNull String EMPTY_STRING
= ""; //$NON-NLS-1$
74 private static final int INTEGER_BASE_16
= 16;
75 private static final int INTEGER_BASE_10
= 10;
76 private static final int INTEGER_BASE_8
= 8;
77 private static final int INTEGER_BASE_2
= 2;
78 private static final long DEFAULT_ALIGNMENT
= 8;
79 private static final int DEFAULT_FLOAT_EXPONENT
= 8;
80 private static final int DEFAULT_FLOAT_MANTISSA
= 24;
81 private static final int DEFAULT_INT_BASE
= 10;
85 private final CTFTrace fTrace
;
86 private CommonTree fTree
;
89 * The current declaration scope.
91 private DeclarationScope fScope
= null;
94 * Data helpers needed for streaming
97 private boolean fHasBeenParsed
= false;
99 // ------------------------------------------------------------------------
101 // ------------------------------------------------------------------------
107 * the tree (ANTLR generated) with the parsed TSDL data.
109 * the trace containing the places to put all the read metadata
111 public IOStructGen(CommonTree tree
, CTFTrace trace
) {
118 * Parse the tree and populate the trace defined in the constructor.
120 * @throws ParseException
121 * If there was a problem parsing the metadata
123 public void generate() throws ParseException
{
128 * Parse a partial tree and populate the trace defined in the constructor.
129 * Does not check for a "trace" block as there is only one in the trace and
132 * @throws ParseException
133 * If there was a problem parsing the metadata
135 public void generateFragment() throws ParseException
{
136 parseIncompleteRoot(fTree
);
139 // ------------------------------------------------------------------------
141 // ------------------------------------------------------------------------
144 * Sets a new tree to parse
147 * the new tree to parse
149 public void setTree(CommonTree newTree
) {
154 * Parse the root node.
158 * @throws ParseException
160 private void parseRoot(CommonTree root
) throws ParseException
{
162 List
<CommonTree
> children
= root
.getChildren();
164 CommonTree traceNode
= null;
165 boolean hasStreams
= false;
166 List
<CommonTree
> events
= new ArrayList
<>();
168 /* Create a new declaration scope with no parent. */
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
<>();
228 /* Create a new declaration scope with no parent. */
231 for (CommonTree child
: children
) {
232 final int type
= child
.getType();
234 case CTFParser
.DECLARATION
:
235 parseRootDeclaration(child
);
237 case CTFParser
.TRACE
:
238 throw new ParseException("Trace block defined here, please use generate and not generateFragment to parse this fragment"); //$NON-NLS-1$
239 case CTFParser
.STREAM
:
242 case CTFParser
.EVENT
:
245 case CTFParser
.CLOCK
:
249 parseEnvironment(child
);
251 case CTFParser
.CALLSITE
:
252 parseCallsite(child
);
255 throw childTypeError(child
);
258 parseEvents(events
, !Iterables
.isEmpty(fTrace
.getStreams()));
262 private void parseCallsite(CommonTree callsite
) {
264 List
<CommonTree
> children
= callsite
.getChildren();
266 String funcName
= null;
267 long lineNumber
= -1;
269 String fileName
= null;
271 for (CommonTree child
: children
) {
273 /* this is a regex to find the leading and trailing quotes */
274 final String regex
= "^\"|\"$"; //$NON-NLS-1$
276 * this is to replace the previous quotes with nothing...
277 * effectively deleting them
279 final String nullString
= EMPTY_STRING
;
280 left
= child
.getChild(0).getChild(0).getChild(0).getText();
281 if (left
.equals(NAME
)) {
282 name
= child
.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex
, nullString
);
283 } else if (left
.equals(FUNC
)) {
284 funcName
= child
.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex
, nullString
);
285 } else if (left
.equals(IP
)) {
286 ip
= Long
.decode(child
.getChild(1).getChild(0).getChild(0).getText());
287 } else if (left
.equals(FILE
)) {
288 fileName
= child
.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex
, nullString
);
289 } else if (left
.equals(LINE
)) {
290 lineNumber
= Long
.parseLong(child
.getChild(1).getChild(0).getChild(0).getText());
293 fTrace
.addCallsite(name
, funcName
, ip
, fileName
, lineNumber
);
296 private void parseEnvironment(CommonTree environment
) {
297 List
<CommonTree
> children
= environment
.getChildren();
298 for (CommonTree child
: children
) {
301 left
= child
.getChild(0).getChild(0).getChild(0).getText();
302 right
= child
.getChild(1).getChild(0).getChild(0).getText();
303 fTrace
.addEnvironmentVar(left
, right
);
307 private void parseClock(CommonTree clock
) throws ParseException
{
308 List
<CommonTree
> children
= clock
.getChildren();
309 CTFClock ctfClock
= new CTFClock();
310 for (CommonTree child
: children
) {
311 final String key
= child
.getChild(0).getChild(0).getChild(0).getText();
312 final CommonTree value
= (CommonTree
) child
.getChild(1).getChild(0).getChild(0);
313 final int type
= value
.getType();
314 final String text
= value
.getText();
316 case CTFParser
.INTEGER
:
317 case CTFParser
.DECIMAL_LITERAL
:
319 * Not a pretty hack, this is to make sure that there is no
320 * number overflow due to 63 bit integers. The offset should
321 * only really be an issue in the year 2262. the tracer in C/ASM
322 * can write an offset in an unsigned 64 bit long. In java, the
323 * last bit, being set to 1 will be read as a negative number,
324 * but since it is too big a positive it will throw an
325 * exception. this will happen in 2^63 ns from 1970. Therefore
326 * 293 years from 1970
330 numValue
= Long
.parseLong(text
);
331 } catch (NumberFormatException e
) {
332 throw new ParseException("Number conversion issue with " + text
, e
); //$NON-NLS-1$
334 ctfClock
.addAttribute(key
, numValue
);
337 ctfClock
.addAttribute(key
, text
);
341 String nameValue
= ctfClock
.getName();
342 fTrace
.addClock(nameValue
, ctfClock
);
345 private void parseTrace(CommonTree traceNode
) throws ParseException
{
347 List
<CommonTree
> children
= traceNode
.getChildren();
348 if (children
== null) {
349 throw new ParseException("Trace block is empty"); //$NON-NLS-1$
354 for (CommonTree child
: children
) {
355 switch (child
.getType()) {
356 case CTFParser
.TYPEALIAS
:
357 parseTypealias(child
);
359 case CTFParser
.TYPEDEF
:
362 case CTFParser
.CTF_EXPRESSION_TYPE
:
363 case CTFParser
.CTF_EXPRESSION_VAL
:
364 parseTraceDeclaration(child
);
367 throw childTypeError(child
);
372 * If trace byte order was not specified and not using packet based
375 if (fTrace
.getByteOrder() == null) {
376 throw new ParseException("Trace byte order not set"); //$NON-NLS-1$
382 private void parseTraceDeclaration(CommonTree traceDecl
)
383 throws ParseException
{
385 /* There should be a left and right */
387 CommonTree leftNode
= (CommonTree
) traceDecl
.getChild(0);
388 CommonTree rightNode
= (CommonTree
) traceDecl
.getChild(1);
390 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
392 if (!isAnyUnaryString(leftStrings
.get(0))) {
393 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
396 String left
= concatenateUnaryStrings(leftStrings
);
398 if (left
.equals(MetadataStrings
.MAJOR
)) {
399 if (fTrace
.majorIsSet()) {
400 throw new ParseException("major is already set"); //$NON-NLS-1$
403 fTrace
.setMajor(getMajorOrMinor(rightNode
));
404 } else if (left
.equals(MetadataStrings
.MINOR
)) {
405 if (fTrace
.minorIsSet()) {
406 throw new ParseException("minor is already set"); //$NON-NLS-1$
409 fTrace
.setMinor(getMajorOrMinor(rightNode
));
410 } else if (left
.equals(MetadataStrings
.UUID_STRING
)) {
411 UUID uuid
= getUUID(rightNode
);
414 * If uuid was already set by a metadata packet, compare it to see
417 if (fTrace
.uuidIsSet()) {
418 if (fTrace
.getUUID().compareTo(uuid
) != 0) {
419 throw new ParseException("UUID mismatch. Packet says " //$NON-NLS-1$
420 + fTrace
.getUUID() + " but metadata says " + uuid
); //$NON-NLS-1$
423 fTrace
.setUUID(uuid
);
426 } else if (left
.equals(MetadataStrings
.BYTE_ORDER
)) {
427 ByteOrder byteOrder
= getByteOrder(rightNode
);
430 * If byte order was already set by a metadata packet, compare it to
433 if (fTrace
.getByteOrder() != null) {
434 if (fTrace
.getByteOrder() != byteOrder
) {
435 throw new ParseException(
436 "Endianness mismatch. Magic number says " //$NON-NLS-1$
437 + fTrace
.getByteOrder()
438 + " but metadata says " + byteOrder
); //$NON-NLS-1$
441 fTrace
.setByteOrder(byteOrder
);
442 final DeclarationScope parentScope
= fScope
.getParentScope();
444 for (String type
: parentScope
.getTypeNames()) {
445 IDeclaration d
= parentScope
.lookupType(type
);
446 if (d
instanceof IntegerDeclaration
) {
447 addByteOrder(byteOrder
, parentScope
, type
, (IntegerDeclaration
) d
);
448 } else if (d
instanceof StructDeclaration
) {
449 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
453 } else if (left
.equals(MetadataStrings
.PACKET_HEADER
)) {
454 if (fTrace
.packetHeaderIsSet()) {
455 throw new ParseException("packet.header already defined"); //$NON-NLS-1$
458 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
460 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
461 throw new ParseException("packet.header expects a type specifier"); //$NON-NLS-1$
464 IDeclaration packetHeaderDecl
= parseTypeSpecifierList(
465 typeSpecifier
, null);
467 if (!(packetHeaderDecl
instanceof StructDeclaration
)) {
468 throw new ParseException("packet.header expects a struct"); //$NON-NLS-1$
471 fTrace
.setPacketHeader((StructDeclaration
) packetHeaderDecl
);
473 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownTraceAttributeWarning
+ " " + left
); //$NON-NLS-1$
477 private static void addByteOrder(ByteOrder byteOrder
,
478 final DeclarationScope parentScope
, String name
,
479 IntegerDeclaration decl
) throws ParseException
{
481 if (decl
.getByteOrder() != byteOrder
) {
482 IntegerDeclaration newI
;
483 newI
= IntegerDeclaration
.createDeclaration(decl
.getLength(), decl
.isSigned(),
484 decl
.getBase(), byteOrder
, decl
.getEncoding(),
485 decl
.getClock(), decl
.getAlignment());
486 parentScope
.replaceType(name
, newI
);
490 private void setAlign(DeclarationScope parentScope
, StructDeclaration sd
,
491 ByteOrder byteOrder
) throws ParseException
{
493 for (String s
: sd
.getFieldsList()) {
494 IDeclaration d
= sd
.getField(s
);
496 if (d
instanceof StructDeclaration
) {
497 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
499 } else if (d
instanceof VariantDeclaration
) {
500 setAlign(parentScope
, (VariantDeclaration
) d
, byteOrder
);
501 } else if (d
instanceof IntegerDeclaration
) {
502 IntegerDeclaration decl
= (IntegerDeclaration
) d
;
503 if (decl
.getByteOrder() != byteOrder
) {
504 IntegerDeclaration newI
;
505 newI
= IntegerDeclaration
.createDeclaration(decl
.getLength(),
506 decl
.isSigned(), decl
.getBase(), byteOrder
,
507 decl
.getEncoding(), decl
.getClock(),
508 decl
.getAlignment());
509 sd
.getFields().put(s
, newI
);
515 private void setAlign(DeclarationScope parentScope
, VariantDeclaration vd
,
516 ByteOrder byteOrder
) throws ParseException
{
518 for (String s
: vd
.getFields().keySet()) {
519 IDeclaration d
= vd
.getFields().get(s
);
521 if (d
instanceof StructDeclaration
) {
522 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
524 } else if (d
instanceof IntegerDeclaration
) {
525 IntegerDeclaration decl
= (IntegerDeclaration
) d
;
526 IntegerDeclaration newI
;
527 newI
= IntegerDeclaration
.createDeclaration(decl
.getLength(),
528 decl
.isSigned(), decl
.getBase(), byteOrder
,
529 decl
.getEncoding(), decl
.getClock(),
530 decl
.getAlignment());
531 vd
.getFields().put(s
, newI
);
536 private void parseStream(CommonTree streamNode
) throws ParseException
{
538 CTFStream stream
= new CTFStream(fTrace
);
540 List
<CommonTree
> children
= streamNode
.getChildren();
541 if (children
== null) {
542 throw new ParseException("Empty stream block"); //$NON-NLS-1$
547 for (CommonTree child
: children
) {
548 switch (child
.getType()) {
549 case CTFParser
.TYPEALIAS
:
550 parseTypealias(child
);
552 case CTFParser
.TYPEDEF
:
555 case CTFParser
.CTF_EXPRESSION_TYPE
:
556 case CTFParser
.CTF_EXPRESSION_VAL
:
557 parseStreamDeclaration(child
, stream
);
560 throw childTypeError(child
);
564 if (stream
.isIdSet() &&
565 (!fTrace
.packetHeaderIsSet() || !fTrace
.getPacketHeader().hasField(MetadataStrings
.STREAM_ID
))) {
566 throw new ParseException("Stream has an ID, but there is no stream_id field in packet header."); //$NON-NLS-1$
569 fTrace
.addStream(stream
);
574 private void parseStreamDeclaration(CommonTree streamDecl
, CTFStream stream
)
575 throws ParseException
{
577 /* There should be a left and right */
579 CommonTree leftNode
= (CommonTree
) streamDecl
.getChild(0);
580 CommonTree rightNode
= (CommonTree
) streamDecl
.getChild(1);
582 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
584 if (!isAnyUnaryString(leftStrings
.get(0))) {
585 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
588 String left
= concatenateUnaryStrings(leftStrings
);
590 if (left
.equals(MetadataStrings
.ID
)) {
591 if (stream
.isIdSet()) {
592 throw new ParseException("stream id already defined"); //$NON-NLS-1$
595 long streamID
= getStreamID(rightNode
);
597 stream
.setId(streamID
);
598 } else if (left
.equals(MetadataStrings
.EVENT_HEADER
)) {
599 if (stream
.isEventHeaderSet()) {
600 throw new ParseException("event.header already defined"); //$NON-NLS-1$
603 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
605 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
606 throw new ParseException("event.header expects a type specifier"); //$NON-NLS-1$
609 IDeclaration eventHeaderDecl
= parseTypeSpecifierList(
610 typeSpecifier
, null);
612 if (eventHeaderDecl
instanceof StructDeclaration
) {
613 stream
.setEventHeader((StructDeclaration
) eventHeaderDecl
);
614 } else if (eventHeaderDecl
instanceof IEventHeaderDeclaration
) {
615 stream
.setEventHeader((IEventHeaderDeclaration
) eventHeaderDecl
);
617 throw new ParseException("event.header expects a struct"); //$NON-NLS-1$
620 } else if (left
.equals(MetadataStrings
.EVENT_CONTEXT
)) {
621 if (stream
.isEventContextSet()) {
622 throw new ParseException("event.context already defined"); //$NON-NLS-1$
625 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
627 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
628 throw new ParseException("event.context expects a type specifier"); //$NON-NLS-1$
631 IDeclaration eventContextDecl
= parseTypeSpecifierList(
632 typeSpecifier
, null);
634 if (!(eventContextDecl
instanceof StructDeclaration
)) {
635 throw new ParseException("event.context expects a struct"); //$NON-NLS-1$
638 stream
.setEventContext((StructDeclaration
) eventContextDecl
);
639 } else if (left
.equals(MetadataStrings
.PACKET_CONTEXT
)) {
640 if (stream
.isPacketContextSet()) {
641 throw new ParseException("packet.context already defined"); //$NON-NLS-1$
644 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
646 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
647 throw new ParseException("packet.context expects a type specifier"); //$NON-NLS-1$
650 IDeclaration packetContextDecl
= parseTypeSpecifierList(
651 typeSpecifier
, null);
653 if (!(packetContextDecl
instanceof StructDeclaration
)) {
654 throw new ParseException("packet.context expects a struct"); //$NON-NLS-1$
657 stream
.setPacketContext((StructDeclaration
) packetContextDecl
);
659 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownStreamAttributeWarning
+ " " + left
); //$NON-NLS-1$
663 private void parseEvent(CommonTree eventNode
) throws ParseException
{
665 List
<CommonTree
> children
= eventNode
.getChildren();
666 if (children
== null) {
667 throw new ParseException("Empty event block"); //$NON-NLS-1$
670 EventDeclaration event
= new EventDeclaration();
674 for (CommonTree child
: children
) {
675 switch (child
.getType()) {
676 case CTFParser
.TYPEALIAS
:
677 parseTypealias(child
);
679 case CTFParser
.TYPEDEF
:
682 case CTFParser
.CTF_EXPRESSION_TYPE
:
683 case CTFParser
.CTF_EXPRESSION_VAL
:
684 parseEventDeclaration(child
, event
);
687 throw childTypeError(child
);
691 if (!event
.nameIsSet()) {
692 throw new ParseException("Event name not set"); //$NON-NLS-1$
696 * If the event did not specify a stream, then the trace must be single
699 if (!event
.streamIsSet()) {
700 if (fTrace
.nbStreams() > 1) {
701 throw new ParseException("Event without stream_id with more than one stream"); //$NON-NLS-1$
705 * If the event did not specify a stream, the only existing stream
706 * must not have an id. Note: That behavior could be changed, it
707 * could be possible to just get the only existing stream, whatever
710 CTFStream stream
= fTrace
.getStream(null);
712 if (stream
!= null) {
713 event
.setStream(stream
);
715 throw new ParseException("Event without stream_id, but there is no stream without id"); //$NON-NLS-1$
720 * Add the event to the stream.
722 event
.getStream().addEvent(event
);
727 private void parseEventDeclaration(CommonTree eventDecl
,
728 EventDeclaration event
) throws ParseException
{
730 /* There should be a left and right */
732 CommonTree leftNode
= (CommonTree
) eventDecl
.getChild(0);
733 CommonTree rightNode
= (CommonTree
) eventDecl
.getChild(1);
735 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
737 if (!isAnyUnaryString(leftStrings
.get(0))) {
738 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
741 String left
= concatenateUnaryStrings(leftStrings
);
743 if (left
.equals(MetadataStrings
.NAME2
)) {
744 if (event
.nameIsSet()) {
745 throw new ParseException("name already defined"); //$NON-NLS-1$
748 String name
= getEventName(rightNode
);
751 } else if (left
.equals(MetadataStrings
.ID
)) {
752 if (event
.idIsSet()) {
753 throw new ParseException("id already defined"); //$NON-NLS-1$
756 long id
= getEventID(rightNode
);
757 if (id
> Integer
.MAX_VALUE
) {
758 throw new ParseException("id is greater than int.maxvalue, unsupported. id : " + id
); //$NON-NLS-1$
761 throw new ParseException("negative id, unsupported. id : " + id
); //$NON-NLS-1$
763 event
.setId((int) id
);
764 } else if (left
.equals(MetadataStrings
.STREAM_ID
)) {
765 if (event
.streamIsSet()) {
766 throw new ParseException("stream id already defined"); //$NON-NLS-1$
769 long streamId
= getStreamID(rightNode
);
771 CTFStream stream
= fTrace
.getStream(streamId
);
773 if (stream
== null) {
774 throw new ParseException("Stream " + streamId
+ " not found"); //$NON-NLS-1$ //$NON-NLS-2$
777 event
.setStream(stream
);
778 } else if (left
.equals(MetadataStrings
.CONTEXT
)) {
779 if (event
.contextIsSet()) {
780 throw new ParseException("context already defined"); //$NON-NLS-1$
783 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
785 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
786 throw new ParseException("context expects a type specifier"); //$NON-NLS-1$
789 IDeclaration contextDecl
= parseTypeSpecifierList(typeSpecifier
,
792 if (!(contextDecl
instanceof StructDeclaration
)) {
793 throw new ParseException("context expects a struct"); //$NON-NLS-1$
796 event
.setContext((StructDeclaration
) contextDecl
);
797 } else if (left
.equals(MetadataStrings
.FIELDS_STRING
)) {
798 if (event
.fieldsIsSet()) {
799 throw new ParseException("fields already defined"); //$NON-NLS-1$
802 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
804 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
805 throw new ParseException("fields expects a type specifier"); //$NON-NLS-1$
808 IDeclaration fieldsDecl
;
809 fieldsDecl
= parseTypeSpecifierList(typeSpecifier
, null);
811 if (!(fieldsDecl
instanceof StructDeclaration
)) {
812 throw new ParseException("fields expects a struct"); //$NON-NLS-1$
815 * The underscores in the event names. These underscores were added
816 * by the LTTng tracer.
818 final StructDeclaration fields
= (StructDeclaration
) fieldsDecl
;
819 event
.setFields(fields
);
820 } else if (left
.equals(MetadataStrings
.LOGLEVEL2
)) {
821 long logLevel
= parseUnaryInteger((CommonTree
) rightNode
.getChild(0));
822 event
.setLogLevel(logLevel
);
824 /* Custom event attribute, we'll add it to the attributes map */
825 String right
= parseUnaryString((CommonTree
) rightNode
.getChild(0));
826 event
.setCustomAttribute(left
, right
);
831 * Parses a declaration at the root level.
834 * The declaration subtree.
835 * @throws ParseException
837 private void parseRootDeclaration(CommonTree declaration
)
838 throws ParseException
{
840 List
<CommonTree
> children
= declaration
.getChildren();
842 for (CommonTree child
: children
) {
843 switch (child
.getType()) {
844 case CTFParser
.TYPEDEF
:
847 case CTFParser
.TYPEALIAS
:
848 parseTypealias(child
);
850 case CTFParser
.TYPE_SPECIFIER_LIST
:
851 parseTypeSpecifierList(child
, null);
854 throw childTypeError(child
);
860 * Parses a typealias node. It parses the target, the alias, and registers
861 * the type in the current scope.
865 * @throws ParseException
867 private void parseTypealias(CommonTree typealias
) throws ParseException
{
869 List
<CommonTree
> children
= typealias
.getChildren();
871 CommonTree target
= null;
872 CommonTree alias
= null;
874 for (CommonTree child
: children
) {
875 switch (child
.getType()) {
876 case CTFParser
.TYPEALIAS_TARGET
:
879 case CTFParser
.TYPEALIAS_ALIAS
:
883 throw childTypeError(child
);
887 IDeclaration targetDeclaration
= parseTypealiasTarget(target
);
889 if ((targetDeclaration
instanceof VariantDeclaration
)
890 && ((VariantDeclaration
) targetDeclaration
).isTagged()) {
891 throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
894 String aliasString
= parseTypealiasAlias(alias
);
896 getCurrentScope().registerType(aliasString
, targetDeclaration
);
900 * Parses the target part of a typealias and gets the corresponding
904 * A TYPEALIAS_TARGET node.
905 * @return The corresponding declaration.
906 * @throws ParseException
908 private IDeclaration
parseTypealiasTarget(CommonTree target
)
909 throws ParseException
{
911 List
<CommonTree
> children
= target
.getChildren();
913 CommonTree typeSpecifierList
= null;
914 CommonTree typeDeclaratorList
= null;
915 CommonTree typeDeclarator
= null;
916 StringBuilder identifierSB
= new StringBuilder();
918 for (CommonTree child
: children
) {
919 switch (child
.getType()) {
920 case CTFParser
.TYPE_SPECIFIER_LIST
:
921 typeSpecifierList
= child
;
923 case CTFParser
.TYPE_DECLARATOR_LIST
:
924 typeDeclaratorList
= child
;
927 throw childTypeError(child
);
931 if (typeDeclaratorList
!= null) {
933 * Only allow one declarator
935 * eg: "typealias uint8_t *, ** := puint8_t;" is not permitted,
936 * otherwise the new type puint8_t would maps to two different
939 if (typeDeclaratorList
.getChildCount() != 1) {
940 throw new ParseException("Only one type declarator is allowed in the typealias target"); //$NON-NLS-1$
943 typeDeclarator
= (CommonTree
) typeDeclaratorList
.getChild(0);
946 /* Parse the target type and get the declaration */
947 IDeclaration targetDeclaration
= parseTypeDeclarator(typeDeclarator
,
948 typeSpecifierList
, identifierSB
);
951 * We don't allow identifier in the target
953 * eg: "typealias uint8_t* hello := puint8_t;", the "hello" is not
956 if (identifierSB
.length() > 0) {
957 throw new ParseException("Identifier (" + identifierSB
.toString() //$NON-NLS-1$
958 + ") not expected in the typealias target"); //$NON-NLS-1$
961 return targetDeclaration
;
965 * Parses the alias part of a typealias. It parses the underlying specifier
966 * list and declarator and creates the string representation that will be
967 * used to register the type.
970 * A TYPEALIAS_ALIAS node.
971 * @return The string representation of the alias.
972 * @throws ParseException
974 private static String
parseTypealiasAlias(CommonTree alias
)
975 throws ParseException
{
977 List
<CommonTree
> children
= alias
.getChildren();
979 CommonTree typeSpecifierList
= null;
980 CommonTree typeDeclaratorList
= null;
981 CommonTree typeDeclarator
= null;
982 List
<CommonTree
> pointers
= new LinkedList
<>();
984 for (CommonTree child
: children
) {
985 switch (child
.getType()) {
986 case CTFParser
.TYPE_SPECIFIER_LIST
:
987 typeSpecifierList
= child
;
989 case CTFParser
.TYPE_DECLARATOR_LIST
:
990 typeDeclaratorList
= child
;
993 throw childTypeError(child
);
997 /* If there is a type declarator list, extract the pointers */
998 if (typeDeclaratorList
!= null) {
1000 * Only allow one declarator
1002 * eg: "typealias uint8_t := puint8_t *, **;" is not permitted.
1004 if (typeDeclaratorList
.getChildCount() != 1) {
1005 throw new ParseException("Only one type declarator is allowed in the typealias alias"); //$NON-NLS-1$
1008 typeDeclarator
= (CommonTree
) typeDeclaratorList
.getChild(0);
1010 List
<CommonTree
> typeDeclaratorChildren
= typeDeclarator
.getChildren();
1012 for (CommonTree child
: typeDeclaratorChildren
) {
1013 switch (child
.getType()) {
1014 case CTFParser
.POINTER
:
1015 pointers
.add(child
);
1017 case CTFParser
.IDENTIFIER
:
1018 throw new ParseException("Identifier (" + child
.getText() //$NON-NLS-1$
1019 + ") not expected in the typealias target"); //$NON-NLS-1$
1021 throw childTypeError(child
);
1026 return createTypeDeclarationString(typeSpecifierList
, pointers
);
1030 * Parses a typedef node. This creates and registers a new declaration for
1031 * each declarator found in the typedef.
1035 * @throws ParseException
1036 * If there is an error creating the declaration.
1038 private void parseTypedef(CommonTree typedef
) throws ParseException
{
1040 CommonTree typeDeclaratorListNode
= (CommonTree
) typedef
.getFirstChildWithType(CTFParser
.TYPE_DECLARATOR_LIST
);
1042 CommonTree typeSpecifierListNode
= (CommonTree
) typedef
.getFirstChildWithType(CTFParser
.TYPE_SPECIFIER_LIST
);
1044 List
<CommonTree
> typeDeclaratorList
= typeDeclaratorListNode
.getChildren();
1046 for (CommonTree typeDeclaratorNode
: typeDeclaratorList
) {
1047 StringBuilder identifierSB
= new StringBuilder();
1049 IDeclaration typeDeclaration
= parseTypeDeclarator(
1050 typeDeclaratorNode
, typeSpecifierListNode
, identifierSB
);
1052 if ((typeDeclaration
instanceof VariantDeclaration
)
1053 && ((VariantDeclaration
) typeDeclaration
).isTagged()) {
1054 throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$
1057 getCurrentScope().registerType(identifierSB
.toString(),
1063 * Parses a pair type declarator / type specifier list and returns the
1064 * corresponding declaration. If it is present, it also writes the
1065 * identifier of the declarator in the given {@link StringBuilder}.
1067 * @param typeDeclarator
1068 * A TYPE_DECLARATOR node.
1069 * @param typeSpecifierList
1070 * A TYPE_SPECIFIER_LIST node.
1071 * @param identifierSB
1072 * A StringBuilder that will receive the identifier found in the
1074 * @return The corresponding declaration.
1075 * @throws ParseException
1076 * If there is an error finding or creating the declaration.
1078 private IDeclaration
parseTypeDeclarator(CommonTree typeDeclarator
,
1079 CommonTree typeSpecifierList
, StringBuilder identifierSB
)
1080 throws ParseException
{
1082 IDeclaration declaration
= null;
1083 List
<CommonTree
> children
= null;
1084 List
<CommonTree
> pointers
= new LinkedList
<>();
1085 List
<CommonTree
> lengths
= new LinkedList
<>();
1086 CommonTree identifier
= null;
1088 /* Separate the tokens by type */
1089 if (typeDeclarator
!= null) {
1090 children
= typeDeclarator
.getChildren();
1091 for (CommonTree child
: children
) {
1093 switch (child
.getType()) {
1094 case CTFParser
.POINTER
:
1095 pointers
.add(child
);
1097 case CTFParser
.IDENTIFIER
:
1100 case CTFParser
.LENGTH
:
1104 throw childTypeError(child
);
1111 * Parse the type specifier list, which is the "base" type. For example,
1112 * it would be int in int a[3][len].
1114 declaration
= parseTypeSpecifierList(typeSpecifierList
, pointers
);
1117 * Each length subscript means that we must create a nested array or
1118 * sequence. For example, int a[3][len] means that we have an array of 3
1119 * (sequences of length 'len' of (int)).
1121 if (!lengths
.isEmpty()) {
1122 /* We begin at the end */
1123 Collections
.reverse(lengths
);
1125 for (CommonTree length
: lengths
) {
1127 * By looking at the first expression, we can determine whether
1128 * it is an array or a sequence.
1130 List
<CommonTree
> lengthChildren
= length
.getChildren();
1132 CommonTree first
= lengthChildren
.get(0);
1133 if (isUnaryInteger(first
)) {
1135 int arrayLength
= (int) parseUnaryInteger(first
);
1137 if (arrayLength
< 1) {
1138 throw new ParseException("Array length is negative"); //$NON-NLS-1$
1141 /* Create the array declaration. */
1142 declaration
= new ArrayDeclaration(arrayLength
, declaration
);
1143 } else if (isAnyUnaryString(first
)) {
1145 String lengthName
= concatenateUnaryStrings(lengthChildren
);
1147 /* check that lengthName was declared */
1148 if (isSignedIntegerField(lengthName
)) {
1149 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
1151 /* Create the sequence declaration. */
1152 declaration
= new SequenceDeclaration(lengthName
,
1155 throw childTypeError(first
);
1160 if (identifier
!= null) {
1161 identifierSB
.append(identifier
.getText());
1167 private boolean isSignedIntegerField(String lengthName
) throws ParseException
{
1168 IDeclaration decl
= getCurrentScope().lookupIdentifierRecursive(lengthName
);
1169 if (decl
instanceof IntegerDeclaration
) {
1170 return ((IntegerDeclaration
) decl
).isSigned();
1172 throw new ParseException("Is not an integer: " + lengthName
); //$NON-NLS-1$
1177 * Parses a type specifier list and returns the corresponding declaration.
1179 * @param typeSpecifierList
1180 * A TYPE_SPECIFIER_LIST node.
1181 * @param pointerList
1182 * A list of POINTER nodes that apply to the specified type.
1183 * @return The corresponding declaration.
1184 * @throws ParseException
1185 * If the type has not been defined or if there is an error
1186 * creating the declaration.
1188 private IDeclaration
parseTypeSpecifierList(CommonTree typeSpecifierList
,
1189 List
<CommonTree
> pointerList
) throws ParseException
{
1190 IDeclaration declaration
= null;
1193 * By looking at the first element of the type specifier list, we can
1194 * determine which type it belongs to.
1196 CommonTree firstChild
= (CommonTree
) typeSpecifierList
.getChild(0);
1198 switch (firstChild
.getType()) {
1199 case CTFParser
.FLOATING_POINT
:
1200 declaration
= parseFloat(firstChild
);
1202 case CTFParser
.INTEGER
:
1203 declaration
= parseInteger(firstChild
);
1205 case CTFParser
.STRING
:
1206 declaration
= parseString(firstChild
);
1208 case CTFParser
.STRUCT
:
1209 declaration
= parseStruct(firstChild
);
1210 StructDeclaration structDeclaration
= (StructDeclaration
) declaration
;
1211 IDeclaration idEnumDecl
= structDeclaration
.getFields().get("id"); //$NON-NLS-1$
1212 if (idEnumDecl
instanceof EnumDeclaration
) {
1213 EnumDeclaration enumDeclaration
= (EnumDeclaration
) idEnumDecl
;
1214 ByteOrder bo
= enumDeclaration
.getContainerType().getByteOrder();
1215 if (EventHeaderCompactDeclaration
.getEventHeader(bo
).isCompactEventHeader(structDeclaration
)) {
1216 declaration
= EventHeaderCompactDeclaration
.getEventHeader(bo
);
1217 } else if (EventHeaderLargeDeclaration
.getEventHeader(bo
).isLargeEventHeader(structDeclaration
)) {
1218 declaration
= EventHeaderLargeDeclaration
.getEventHeader(bo
);
1222 case CTFParser
.VARIANT
:
1223 declaration
= parseVariant(firstChild
);
1225 case CTFParser
.ENUM
:
1226 declaration
= parseEnum(firstChild
);
1228 case CTFParser
.IDENTIFIER
:
1229 case CTFParser
.FLOATTOK
:
1230 case CTFParser
.INTTOK
:
1231 case CTFParser
.LONGTOK
:
1232 case CTFParser
.SHORTTOK
:
1233 case CTFParser
.SIGNEDTOK
:
1234 case CTFParser
.UNSIGNEDTOK
:
1235 case CTFParser
.CHARTOK
:
1236 case CTFParser
.DOUBLETOK
:
1237 case CTFParser
.VOIDTOK
:
1238 case CTFParser
.BOOLTOK
:
1239 case CTFParser
.COMPLEXTOK
:
1240 case CTFParser
.IMAGINARYTOK
:
1241 declaration
= parseTypeDeclaration(typeSpecifierList
, pointerList
);
1244 throw childTypeError(firstChild
);
1250 private IDeclaration
parseFloat(CommonTree floatingPoint
)
1251 throws ParseException
{
1253 List
<CommonTree
> children
= floatingPoint
.getChildren();
1256 * If the integer has no attributes, then it is missing the size
1257 * attribute which is required
1259 if (children
== null) {
1260 throw new ParseException("float: missing size attribute"); //$NON-NLS-1$
1263 /* The return value */
1264 FloatDeclaration floatDeclaration
= null;
1265 ByteOrder byteOrder
= fTrace
.getByteOrder();
1268 int exponent
= DEFAULT_FLOAT_EXPONENT
;
1269 int mantissa
= DEFAULT_FLOAT_MANTISSA
;
1271 /* Iterate on all integer children */
1272 for (CommonTree child
: children
) {
1273 switch (child
.getType()) {
1274 case CTFParser
.CTF_EXPRESSION_VAL
:
1276 * An assignment expression must have 2 children, left and right
1279 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1280 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1282 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1284 if (!isAnyUnaryString(leftStrings
.get(0))) {
1285 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1287 String left
= concatenateUnaryStrings(leftStrings
);
1289 if (left
.equals(MetadataStrings
.EXP_DIG
)) {
1290 exponent
= (int) parseUnaryInteger((CommonTree
) rightNode
.getChild(0));
1291 } else if (left
.equals(MetadataStrings
.BYTE_ORDER
)) {
1292 byteOrder
= getByteOrder(rightNode
);
1293 } else if (left
.equals(MetadataStrings
.MANT_DIG
)) {
1294 mantissa
= (int) parseUnaryInteger((CommonTree
) rightNode
.getChild(0));
1295 } else if (left
.equals(MetadataStrings
.ALIGN
)) {
1296 alignment
= getAlignment(rightNode
);
1298 throw new ParseException("Float: unknown attribute " + left
); //$NON-NLS-1$
1303 throw childTypeError(child
);
1306 int size
= mantissa
+ exponent
;
1308 throw new ParseException("Float missing size attribute"); //$NON-NLS-1$
1311 if (alignment
== 0) {
1312 alignment
= ((size
% DEFAULT_ALIGNMENT
) == 0) ?
1 : DEFAULT_ALIGNMENT
;
1315 floatDeclaration
= new FloatDeclaration(exponent
, mantissa
, byteOrder
, alignment
);
1317 return floatDeclaration
;
1322 * Parses a type specifier list as a user-declared type.
1324 * @param typeSpecifierList
1325 * A TYPE_SPECIFIER_LIST node containing a user-declared type.
1326 * @param pointerList
1327 * A list of POINTER nodes that apply to the type specified in
1328 * typeSpecifierList.
1329 * @return The corresponding declaration.
1330 * @throws ParseException
1331 * If the type does not exist (has not been found).
1333 private IDeclaration
parseTypeDeclaration(CommonTree typeSpecifierList
,
1334 List
<CommonTree
> pointerList
) throws ParseException
{
1335 /* Create the string representation of the type declaration */
1336 String typeStringRepresentation
= createTypeDeclarationString(
1337 typeSpecifierList
, pointerList
);
1339 /* Use the string representation to search the type in the current scope */
1340 IDeclaration decl
= getCurrentScope().lookupTypeRecursive(
1341 typeStringRepresentation
);
1344 throw new ParseException("Type " + typeStringRepresentation
//$NON-NLS-1$
1345 + " has not been defined."); //$NON-NLS-1$
1352 * Parses an integer declaration node.
1356 * @return The corresponding integer declaration.
1357 * @throws ParseException
1359 private IntegerDeclaration
parseInteger(CommonTree integer
)
1360 throws ParseException
{
1362 List
<CommonTree
> children
= integer
.getChildren();
1365 * If the integer has no attributes, then it is missing the size
1366 * attribute which is required
1368 if (children
== null) {
1369 throw new ParseException("integer: missing size attribute"); //$NON-NLS-1$
1372 /* The return value */
1373 IntegerDeclaration integerDeclaration
= null;
1374 boolean signed
= false;
1375 ByteOrder byteOrder
= fTrace
.getByteOrder();
1378 int base
= DEFAULT_INT_BASE
;
1380 String clock
= EMPTY_STRING
;
1382 Encoding encoding
= Encoding
.NONE
;
1384 /* Iterate on all integer children */
1385 for (CommonTree child
: children
) {
1386 switch (child
.getType()) {
1387 case CTFParser
.CTF_EXPRESSION_VAL
:
1389 * An assignment expression must have 2 children, left and right
1392 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1393 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1395 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1397 if (!isAnyUnaryString(leftStrings
.get(0))) {
1398 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1400 String left
= concatenateUnaryStrings(leftStrings
);
1402 if (left
.equals(SIGNED
)) {
1403 signed
= getSigned(rightNode
);
1404 } else if (left
.equals(MetadataStrings
.BYTE_ORDER
)) {
1405 byteOrder
= getByteOrder(rightNode
);
1406 } else if (left
.equals(SIZE
)) {
1407 size
= getSize(rightNode
);
1408 } else if (left
.equals(MetadataStrings
.ALIGN
)) {
1409 alignment
= getAlignment(rightNode
);
1410 } else if (left
.equals(BASE
)) {
1411 base
= getBase(rightNode
);
1412 } else if (left
.equals(ENCODING
)) {
1413 encoding
= getEncoding(rightNode
);
1414 } else if (left
.equals(MAP
)) {
1415 clock
= getClock(rightNode
);
1417 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownIntegerAttributeWarning
+ " " + left
); //$NON-NLS-1$
1422 throw childTypeError(child
);
1427 throw new ParseException("Invalid size attribute in Integer: " + size
); //$NON-NLS-1$
1430 if (alignment
== 0) {
1431 alignment
= ((size
% DEFAULT_ALIGNMENT
) == 0) ?
1 : DEFAULT_ALIGNMENT
;
1434 integerDeclaration
= IntegerDeclaration
.createDeclaration((int) size
, signed
, base
,
1435 byteOrder
, encoding
, clock
, alignment
);
1437 return integerDeclaration
;
1441 private static String
getClock(CommonTree rightNode
) {
1442 String clock
= rightNode
.getChild(1).getChild(0).getChild(0).getText();
1443 return clock
== null ? EMPTY_STRING
: clock
;
1446 private static StringDeclaration
parseString(CommonTree string
)
1447 throws ParseException
{
1449 List
<CommonTree
> children
= string
.getChildren();
1450 StringDeclaration stringDeclaration
= null;
1452 if (children
== null) {
1453 stringDeclaration
= StringDeclaration
.getStringDeclaration(Encoding
.UTF8
);
1455 Encoding encoding
= Encoding
.UTF8
;
1456 for (CommonTree child
: children
) {
1457 switch (child
.getType()) {
1458 case CTFParser
.CTF_EXPRESSION_VAL
:
1460 * An assignment expression must have 2 children, left and
1464 CommonTree leftNode
= (CommonTree
) child
.getChild(0);
1465 CommonTree rightNode
= (CommonTree
) child
.getChild(1);
1467 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
1469 if (!isAnyUnaryString(leftStrings
.get(0))) {
1470 throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$
1472 String left
= concatenateUnaryStrings(leftStrings
);
1474 if (left
.equals(ENCODING
)) {
1475 encoding
= getEncoding(rightNode
);
1477 throw new ParseException("String: unknown attribute " //$NON-NLS-1$
1483 throw childTypeError(child
);
1487 stringDeclaration
= StringDeclaration
.getStringDeclaration(encoding
);
1490 return stringDeclaration
;
1494 * Parses a struct declaration and returns the corresponding declaration.
1498 * @return The corresponding struct declaration.
1499 * @throws ParseException
1501 private StructDeclaration
parseStruct(CommonTree struct
)
1502 throws ParseException
{
1504 List
<CommonTree
> children
= struct
.getChildren();
1506 /* The return value */
1507 StructDeclaration structDeclaration
= null;
1510 String structName
= null;
1511 boolean hasName
= false;
1514 CommonTree structBody
= null;
1515 boolean hasBody
= false;
1518 long structAlign
= 0;
1520 /* Loop on all children and identify what we have to work with. */
1521 for (CommonTree child
: children
) {
1522 switch (child
.getType()) {
1523 case CTFParser
.STRUCT_NAME
: {
1526 CommonTree structNameIdentifier
= (CommonTree
) child
.getChild(0);
1528 structName
= structNameIdentifier
.getText();
1532 case CTFParser
.STRUCT_BODY
: {
1539 case CTFParser
.ALIGN
: {
1540 CommonTree structAlignExpression
= (CommonTree
) child
.getChild(0);
1542 structAlign
= getAlignment(structAlignExpression
);
1547 throw childTypeError(child
);
1552 * If a struct has just a body and no name (just like the song,
1553 * "A Struct With No Name" by America (sorry for that...)), it's a
1554 * definition of a new type, so we create the type declaration and
1555 * return it. We can't add it to the declaration scope since there is no
1556 * name, but that's what we want because it won't be possible to use it
1557 * again to declare another field.
1559 * If it has just a name, we look it up in the declaration scope and
1560 * return the associated declaration. If it is not found in the
1561 * declaration scope, it means that a struct with that name has not been
1562 * declared, which is an error.
1564 * If it has both, then we create the type declaration and register it
1565 * to the current scope.
1567 * If it has none, then what are we doing here ?
1571 * If struct has a name, check if already defined in the current
1574 if (hasName
&& (getCurrentScope().lookupStruct(structName
) != null)) {
1575 throw new ParseException("struct " + structName
//$NON-NLS-1$
1576 + " already defined."); //$NON-NLS-1$
1578 /* Create the declaration */
1579 structDeclaration
= new StructDeclaration(structAlign
);
1581 /* Parse the body */
1582 parseStructBody(structBody
, structDeclaration
);
1584 /* If struct has name, add it to the current scope. */
1586 getCurrentScope().registerStruct(structName
, structDeclaration
);
1588 } else /* !hasBody */{
1590 /* Name and !body */
1592 /* Lookup the name in the current scope. */
1593 structDeclaration
= getCurrentScope().lookupStructRecursive(structName
);
1596 * If not found, it means that a struct with such name has not
1599 if (structDeclaration
== null) {
1600 throw new ParseException("struct " + structName
//$NON-NLS-1$
1601 + " is not defined"); //$NON-NLS-1$
1604 /* !Name and !body */
1606 /* We can't do anything with that. */
1607 throw new ParseException("struct with no name and no body"); //$NON-NLS-1$
1610 return StructDeclarationFlattener
.tryFlattenStruct(structDeclaration
);
1614 * Parses a struct body, adding the fields to specified structure
1618 * A STRUCT_BODY node.
1619 * @param structDeclaration
1620 * The struct declaration.
1621 * @throws ParseException
1623 private void parseStructBody(CommonTree structBody
,
1624 StructDeclaration structDeclaration
) throws ParseException
{
1626 List
<CommonTree
> structDeclarations
= structBody
.getChildren();
1629 * If structDeclaration is null, structBody has no children and the
1630 * struct body is empty.
1632 if (structDeclarations
!= null) {
1635 for (CommonTree declarationNode
: structDeclarations
) {
1636 switch (declarationNode
.getType()) {
1637 case CTFParser
.TYPEALIAS
:
1638 parseTypealias(declarationNode
);
1640 case CTFParser
.TYPEDEF
:
1641 parseTypedef(declarationNode
);
1643 case CTFParser
.SV_DECLARATION
:
1644 parseStructDeclaration(declarationNode
, structDeclaration
);
1647 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 enumDecl
= getCurrentScope().lookupEnumRecursive(enumName
);
1754 if (enumDecl
!= null) {
1755 return (EnumDeclaration
) enumDecl
;
1759 IDeclaration decl
= getCurrentScope().lookupTypeRecursive("int"); //$NON-NLS-1$
1762 throw new ParseException("enum container type implicit and type int not defined"); //$NON-NLS-1$
1763 } else if (!(decl
instanceof IntegerDeclaration
)) {
1764 throw new ParseException("enum container type implicit and type int not an integer"); //$NON-NLS-1$
1767 containerTypeDeclaration
= (IntegerDeclaration
) decl
;
1771 * If it has a body, it's a new declaration, otherwise it's a reference
1772 * to an existing declaration. Same logic as struct.
1774 if (enumBody
!= null) {
1776 * If enum has a name, check if already defined in the current
1779 if ((enumName
!= null)
1780 && (getCurrentScope().lookupEnum(enumName
) != null)) {
1781 throw new ParseException("enum " + enumName
//$NON-NLS-1$
1782 + " already defined"); //$NON-NLS-1$
1785 /* Create the declaration */
1786 enumDeclaration
= new EnumDeclaration(containerTypeDeclaration
);
1788 /* Parse the body */
1789 parseEnumBody(enumBody
, enumDeclaration
);
1791 /* If the enum has name, add it to the current scope. */
1792 if (enumName
!= null) {
1793 getCurrentScope().registerEnum(enumName
, enumDeclaration
);
1796 if (enumName
!= null) {
1797 /* Name and !body */
1799 /* Lookup the name in the current scope. */
1800 enumDeclaration
= getCurrentScope().lookupEnumRecursive(enumName
);
1803 * If not found, it means that an enum with such name has not
1806 if (enumDeclaration
== null) {
1807 throw new ParseException("enum " + enumName
//$NON-NLS-1$
1808 + " is not defined"); //$NON-NLS-1$
1811 /* !Name and !body */
1812 throw new ParseException("enum with no name and no body"); //$NON-NLS-1$
1816 return enumDeclaration
;
1821 * Parses an enum body, adding the enumerators to the specified enum
1825 * An ENUM_BODY node.
1826 * @param enumDeclaration
1827 * The enum declaration.
1828 * @throws ParseException
1830 private void parseEnumBody(CommonTree enumBody
,
1831 EnumDeclaration enumDeclaration
) throws ParseException
{
1833 List
<CommonTree
> enumerators
= enumBody
.getChildren();
1834 /* enum body can't be empty (unlike struct). */
1839 * Start at -1, so that if the first enumrator has no explicit value, it
1844 for (CommonTree enumerator
: enumerators
) {
1845 lastHigh
= parseEnumEnumerator(enumerator
, enumDeclaration
,
1854 * Parses an enumerator node and adds an enumerator declaration to an
1855 * enumeration declaration.
1857 * The high value of the range of the last enumerator is needed in case the
1858 * current enumerator does not specify its value.
1861 * An ENUM_ENUMERATOR node.
1862 * @param enumDeclaration
1863 * en enumeration declaration to which will be added the
1866 * The high value of the range of the last enumerator
1867 * @return The high value of the value range of the current enumerator.
1868 * @throws ParseException
1870 private static long parseEnumEnumerator(CommonTree enumerator
,
1871 EnumDeclaration enumDeclaration
, long lastHigh
)
1872 throws ParseException
{
1874 List
<CommonTree
> children
= enumerator
.getChildren();
1876 long low
= 0, high
= 0;
1877 boolean valueSpecified
= false;
1878 String label
= null;
1880 for (CommonTree child
: children
) {
1881 if (isAnyUnaryString(child
)) {
1882 label
= parseUnaryString(child
);
1883 } else if (child
.getType() == CTFParser
.ENUM_VALUE
) {
1885 valueSpecified
= true;
1887 low
= parseUnaryInteger((CommonTree
) child
.getChild(0));
1889 } else if (child
.getType() == CTFParser
.ENUM_VALUE_RANGE
) {
1891 valueSpecified
= true;
1893 low
= parseUnaryInteger((CommonTree
) child
.getChild(0));
1894 high
= parseUnaryInteger((CommonTree
) child
.getChild(1));
1896 throw childTypeError(child
);
1900 if (!valueSpecified
) {
1906 throw new ParseException("enum low value greater than high value"); //$NON-NLS-1$
1909 if (!enumDeclaration
.add(low
, high
, label
)) {
1910 throw new ParseException("enum declarator values overlap."); //$NON-NLS-1$
1913 if (valueSpecified
&& (BigInteger
.valueOf(low
).compareTo(enumDeclaration
.getContainerType().getMinValue()) == -1 ||
1914 BigInteger
.valueOf(high
).compareTo(enumDeclaration
.getContainerType().getMaxValue()) == 1)) {
1915 throw new ParseException("enum value is not in range"); //$NON-NLS-1$
1922 * Parses an enum container type node and returns the corresponding integer
1925 * @param enumContainerType
1926 * An ENUM_CONTAINER_TYPE node.
1927 * @return An integer declaration corresponding to the container type.
1928 * @throws ParseException
1929 * If the type does not parse correctly or if it is not an
1932 private IntegerDeclaration
parseEnumContainerType(
1933 CommonTree enumContainerType
) throws ParseException
{
1935 /* Get the child, which should be a type specifier list */
1936 CommonTree typeSpecifierList
= (CommonTree
) enumContainerType
.getChild(0);
1938 /* Parse it and get the corresponding declaration */
1939 IDeclaration decl
= parseTypeSpecifierList(typeSpecifierList
, null);
1941 /* If is is an integer, return it, else throw an error */
1942 if (decl
instanceof IntegerDeclaration
) {
1943 return (IntegerDeclaration
) decl
;
1945 throw new ParseException("enum container type must be an integer"); //$NON-NLS-1$
1948 private VariantDeclaration
parseVariant(CommonTree variant
)
1949 throws ParseException
{
1951 List
<CommonTree
> children
= variant
.getChildren();
1952 VariantDeclaration variantDeclaration
= null;
1954 boolean hasName
= false;
1955 String variantName
= null;
1957 boolean hasBody
= false;
1958 CommonTree variantBody
= null;
1960 boolean hasTag
= false;
1961 String variantTag
= null;
1963 for (CommonTree child
: children
) {
1964 switch (child
.getType()) {
1965 case CTFParser
.VARIANT_NAME
:
1969 CommonTree variantNameIdentifier
= (CommonTree
) child
.getChild(0);
1971 variantName
= variantNameIdentifier
.getText();
1974 case CTFParser
.VARIANT_TAG
:
1978 CommonTree variantTagIdentifier
= (CommonTree
) child
.getChild(0);
1980 variantTag
= variantTagIdentifier
.getText();
1983 case CTFParser
.VARIANT_BODY
:
1987 variantBody
= child
;
1991 throw childTypeError(child
);
1997 * If variant has a name, check if already defined in the current
2001 && (getCurrentScope().lookupVariant(variantName
) != null)) {
2002 throw new ParseException("variant " + variantName
//$NON-NLS-1$
2003 + " already defined."); //$NON-NLS-1$
2006 /* Create the declaration */
2007 variantDeclaration
= new VariantDeclaration();
2009 /* Parse the body */
2010 parseVariantBody(variantBody
, variantDeclaration
);
2012 /* If variant has name, add it to the current scope. */
2014 getCurrentScope().registerVariant(variantName
,
2015 variantDeclaration
);
2017 } else /* !hasBody */{
2019 /* Name and !body */
2021 /* Lookup the name in the current scope. */
2022 variantDeclaration
= getCurrentScope().lookupVariantRecursive(
2026 * If not found, it means that a struct with such name has not
2029 if (variantDeclaration
== null) {
2030 throw new ParseException("variant " + variantName
//$NON-NLS-1$
2031 + " is not defined"); //$NON-NLS-1$
2034 /* !Name and !body */
2036 /* We can't do anything with that. */
2037 throw new ParseException("variant with no name and no body"); //$NON-NLS-1$
2042 variantDeclaration
.setTag(variantTag
);
2044 IDeclaration decl
= getCurrentScope().lookupIdentifierRecursive(variantTag
);
2046 throw new ParseException("Variant tag not found: " + variantTag
); //$NON-NLS-1$
2048 if (!(decl
instanceof EnumDeclaration
)) {
2049 throw new ParseException("Variant tag must be an enum: " + variantTag
); //$NON-NLS-1$
2051 EnumDeclaration tagDecl
= (EnumDeclaration
) decl
;
2052 Set
<String
> intersection
= new HashSet
<>(tagDecl
.getLabels());
2053 intersection
.retainAll(variantDeclaration
.getFields().keySet());
2054 if (intersection
.isEmpty()) {
2055 throw new ParseException("Variant contains no values of the tag, impossible to use: " + variantName
); //$NON-NLS-1$
2059 return variantDeclaration
;
2062 private void parseVariantBody(CommonTree variantBody
,
2063 VariantDeclaration variantDeclaration
) throws ParseException
{
2065 List
<CommonTree
> variantDeclarations
= variantBody
.getChildren();
2069 for (CommonTree declarationNode
: variantDeclarations
) {
2070 switch (declarationNode
.getType()) {
2071 case CTFParser
.TYPEALIAS
:
2072 parseTypealias(declarationNode
);
2074 case CTFParser
.TYPEDEF
:
2075 parseTypedef(declarationNode
);
2077 case CTFParser
.SV_DECLARATION
:
2078 parseVariantDeclaration(declarationNode
, variantDeclaration
);
2081 throw childTypeError(declarationNode
);
2088 private void parseVariantDeclaration(CommonTree declaration
,
2089 VariantDeclaration variant
) throws ParseException
{
2091 /* Get the type specifier list node */
2092 CommonTree typeSpecifierListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_SPECIFIER_LIST
);
2094 /* Get the type declarator list node */
2095 CommonTree typeDeclaratorListNode
= (CommonTree
) declaration
.getFirstChildWithType(CTFParser
.TYPE_DECLARATOR_LIST
);
2097 /* Get the type declarator list */
2098 List
<CommonTree
> typeDeclaratorList
= typeDeclaratorListNode
.getChildren();
2101 * For each type declarator, parse the declaration and add a field to
2104 for (CommonTree typeDeclaratorNode
: typeDeclaratorList
) {
2106 StringBuilder identifierSB
= new StringBuilder();
2108 IDeclaration decl
= parseTypeDeclarator(typeDeclaratorNode
,
2109 typeSpecifierListNode
, identifierSB
);
2111 String name
= identifierSB
.toString();
2113 if (variant
.hasField(name
)) {
2114 throw new ParseException("variant: duplicate field " //$NON-NLS-1$
2118 getCurrentScope().registerIdentifier(name
, decl
);
2120 variant
.addField(name
, decl
);
2125 * Creates the string representation of a type declaration (type specifier
2128 * @param typeSpecifierList
2129 * A TYPE_SPECIFIER_LIST node.
2131 * A list of POINTER nodes.
2132 * @return The string representation.
2133 * @throws ParseException
2135 private static String
createTypeDeclarationString(
2136 CommonTree typeSpecifierList
, List
<CommonTree
> pointers
)
2137 throws ParseException
{
2138 StringBuilder sb
= new StringBuilder();
2140 createTypeSpecifierListString(typeSpecifierList
, sb
);
2141 createPointerListString(pointers
, sb
);
2143 return sb
.toString();
2147 * Creates the string representation of a list of type specifiers.
2149 * @param typeSpecifierList
2150 * A TYPE_SPECIFIER_LIST node.
2152 * A StringBuilder to which will be appended the string.
2153 * @throws ParseException
2155 private static void createTypeSpecifierListString(
2156 CommonTree typeSpecifierList
, StringBuilder sb
)
2157 throws ParseException
{
2159 List
<CommonTree
> children
= typeSpecifierList
.getChildren();
2161 boolean firstItem
= true;
2163 for (CommonTree child
: children
) {
2171 /* Append the string that represents this type specifier. */
2172 createTypeSpecifierString(child
, sb
);
2177 * Creates the string representation of a type specifier.
2179 * @param typeSpecifier
2180 * A TYPE_SPECIFIER node.
2182 * A StringBuilder to which will be appended the string.
2183 * @throws ParseException
2185 private static void createTypeSpecifierString(CommonTree typeSpecifier
,
2186 StringBuilder sb
) throws ParseException
{
2187 switch (typeSpecifier
.getType()) {
2188 case CTFParser
.FLOATTOK
:
2189 case CTFParser
.INTTOK
:
2190 case CTFParser
.LONGTOK
:
2191 case CTFParser
.SHORTTOK
:
2192 case CTFParser
.SIGNEDTOK
:
2193 case CTFParser
.UNSIGNEDTOK
:
2194 case CTFParser
.CHARTOK
:
2195 case CTFParser
.DOUBLETOK
:
2196 case CTFParser
.VOIDTOK
:
2197 case CTFParser
.BOOLTOK
:
2198 case CTFParser
.COMPLEXTOK
:
2199 case CTFParser
.IMAGINARYTOK
:
2200 case CTFParser
.CONSTTOK
:
2201 case CTFParser
.IDENTIFIER
:
2202 sb
.append(typeSpecifier
.getText());
2204 case CTFParser
.STRUCT
: {
2205 CommonTree structName
= (CommonTree
) typeSpecifier
.getFirstChildWithType(CTFParser
.STRUCT_NAME
);
2206 if (structName
== null) {
2207 throw new ParseException("nameless struct found in createTypeSpecifierString"); //$NON-NLS-1$
2210 CommonTree structNameIdentifier
= (CommonTree
) structName
.getChild(0);
2212 sb
.append(structNameIdentifier
.getText());
2215 case CTFParser
.VARIANT
: {
2216 CommonTree variantName
= (CommonTree
) typeSpecifier
.getFirstChildWithType(CTFParser
.VARIANT_NAME
);
2217 if (variantName
== null) {
2218 throw new ParseException("nameless variant found in createTypeSpecifierString"); //$NON-NLS-1$
2221 CommonTree variantNameIdentifier
= (CommonTree
) variantName
.getChild(0);
2223 sb
.append(variantNameIdentifier
.getText());
2226 case CTFParser
.ENUM
: {
2227 CommonTree enumName
= (CommonTree
) typeSpecifier
.getFirstChildWithType(CTFParser
.ENUM_NAME
);
2228 if (enumName
== null) {
2229 throw new ParseException("nameless enum found in createTypeSpecifierString"); //$NON-NLS-1$
2232 CommonTree enumNameIdentifier
= (CommonTree
) enumName
.getChild(0);
2234 sb
.append(enumNameIdentifier
.getText());
2237 case CTFParser
.FLOATING_POINT
:
2238 case CTFParser
.INTEGER
:
2239 case CTFParser
.STRING
:
2240 throw new ParseException("CTF type found in createTypeSpecifierString"); //$NON-NLS-1$
2242 throw childTypeError(typeSpecifier
);
2247 * Creates the string representation of a list of pointers.
2249 * @param pointerList
2250 * A list of pointer nodes. If pointerList is null, this function
2253 * A stringbuilder to which will be appended the string.
2255 private static void createPointerListString(List
<CommonTree
> pointerList
,
2257 if (pointerList
== null) {
2261 for (CommonTree pointer
: pointerList
) {
2263 sb
.append(" *"); //$NON-NLS-1$
2264 if (pointer
.getChildCount() > 0) {
2266 sb
.append(" const"); //$NON-NLS-1$
2273 * The node to check.
2274 * @return True if the given node is an unary string.
2276 private static boolean isUnaryString(CommonTree node
) {
2277 return ((node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING
));
2282 * The node to check.
2283 * @return True if the given node is any type of unary string (no quotes,
2286 private static boolean isAnyUnaryString(CommonTree node
) {
2287 return ((node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING
) || (node
.getType() == CTFParser
.UNARY_EXPRESSION_STRING_QUOTES
));
2292 * The node to check.
2293 * @return True if the given node is an unary integer.
2295 private static boolean isUnaryInteger(CommonTree node
) {
2296 return ((node
.getType() == CTFParser
.UNARY_EXPRESSION_DEC
) ||
2297 (node
.getType() == CTFParser
.UNARY_EXPRESSION_HEX
) || (node
.getType() == CTFParser
.UNARY_EXPRESSION_OCT
));
2301 * Parses a unary string node and return the string value.
2303 * @param unaryString
2304 * The unary string node to parse (type UNARY_EXPRESSION_STRING
2305 * or UNARY_EXPRESSION_STRING_QUOTES).
2306 * @return The string value.
2309 * It would be really nice to remove the quotes earlier, such as in the
2312 private static String
parseUnaryString(CommonTree unaryString
) {
2314 CommonTree value
= (CommonTree
) unaryString
.getChild(0);
2315 String strval
= value
.getText();
2318 if (unaryString
.getType() == CTFParser
.UNARY_EXPRESSION_STRING_QUOTES
) {
2319 strval
= strval
.substring(1, strval
.length() - 1);
2326 * Parses an unary integer (dec, hex or oct).
2328 * @param unaryInteger
2329 * An unary integer node.
2330 * @return The integer value.
2331 * @throws ParseException
2332 * on an invalid integer format ("bob" for example)
2334 private static long parseUnaryInteger(CommonTree unaryInteger
) throws ParseException
{
2336 List
<CommonTree
> children
= unaryInteger
.getChildren();
2337 CommonTree value
= children
.get(0);
2338 String strval
= value
.getText();
2342 intval
= Long
.decode(strval
);
2343 } catch (NumberFormatException e
) {
2344 throw new ParseException("Invalid integer format: " + strval
, e
); //$NON-NLS-1$
2347 /* The rest of children are sign */
2348 if ((children
.size() % 2) == 0) {
2354 private static long getMajorOrMinor(CommonTree rightNode
)
2355 throws ParseException
{
2357 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2359 if (isUnaryInteger(firstChild
)) {
2360 if (rightNode
.getChildCount() > 1) {
2361 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2364 long m
= parseUnaryInteger(firstChild
);
2367 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2372 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2375 private static UUID
getUUID(CommonTree rightNode
) throws ParseException
{
2377 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2379 if (isAnyUnaryString(firstChild
)) {
2380 if (rightNode
.getChildCount() > 1) {
2381 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2384 String uuidstr
= parseUnaryString(firstChild
);
2387 return UUID
.fromString(uuidstr
);
2388 } catch (IllegalArgumentException e
) {
2389 throw new ParseException("Invalid format for UUID", e
); //$NON-NLS-1$
2392 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2396 * Gets the value of a "signed" integer attribute.
2400 * @return The "signed" value as a boolean.
2401 * @throws ParseException
2403 private static boolean getSigned(CommonTree rightNode
)
2404 throws ParseException
{
2406 boolean ret
= false;
2407 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2409 if (isUnaryString(firstChild
)) {
2410 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
2412 if (strval
.equals(MetadataStrings
.TRUE
)
2413 || strval
.equals(MetadataStrings
.TRUE2
)) {
2415 } else if (strval
.equals(MetadataStrings
.FALSE
)
2416 || strval
.equals(MetadataStrings
.FALSE2
)) {
2419 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2420 + firstChild
.getChild(0).getText());
2422 } else if (isUnaryInteger(firstChild
)) {
2423 /* Happens if the value is something like "1234.hello" */
2424 if (rightNode
.getChildCount() > 1) {
2425 throw new ParseException("Invalid boolean value"); //$NON-NLS-1$
2428 long intval
= parseUnaryInteger(firstChild
);
2432 } else if (intval
== 0) {
2435 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2436 + firstChild
.getChild(0).getText());
2439 throw new ParseException();
2446 * Gets the value of a "byte_order" integer attribute.
2450 * @return The "byte_order" value.
2451 * @throws ParseException
2453 private ByteOrder
getByteOrder(CommonTree rightNode
) throws ParseException
{
2455 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2457 if (isUnaryString(firstChild
)) {
2458 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
2460 if (strval
.equals(MetadataStrings
.LE
)) {
2461 return ByteOrder
.LITTLE_ENDIAN
;
2462 } else if (strval
.equals(MetadataStrings
.BE
)
2463 || strval
.equals(MetadataStrings
.NETWORK
)) {
2464 return ByteOrder
.BIG_ENDIAN
;
2465 } else if (strval
.equals(MetadataStrings
.NATIVE
)) {
2466 return fTrace
.getByteOrder();
2468 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2471 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2475 * Determines if the given value is a valid alignment value.
2478 * The value to check.
2479 * @return True if it is valid.
2481 private static boolean isValidAlignment(long alignment
) {
2482 return !((alignment
<= 0) || ((alignment
& (alignment
- 1)) != 0));
2486 * Gets the value of a "size" integer attribute.
2490 * @return The "size" value.
2491 * @throws ParseException
2493 private static long getSize(CommonTree rightNode
) throws ParseException
{
2495 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2497 if (isUnaryInteger(firstChild
)) {
2498 if (rightNode
.getChildCount() > 1) {
2499 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2502 long size
= parseUnaryInteger(firstChild
);
2505 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2510 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2514 * Gets the value of a "align" integer or struct attribute.
2517 * A CTF_RIGHT node or directly an unary integer.
2518 * @return The align value.
2519 * @throws ParseException
2521 private static long getAlignment(CommonTree node
) throws ParseException
{
2524 * If a CTF_RIGHT node was passed, call getAlignment with the first
2527 if (node
.getType() == CTFParser
.CTF_RIGHT
) {
2528 if (node
.getChildCount() > 1) {
2529 throw new ParseException("Invalid alignment value"); //$NON-NLS-1$
2532 return getAlignment((CommonTree
) node
.getChild(0));
2533 } else if (isUnaryInteger(node
)) {
2534 long alignment
= parseUnaryInteger(node
);
2536 if (!isValidAlignment(alignment
)) {
2537 throw new ParseException("Invalid value for alignment : " //$NON-NLS-1$
2543 throw new ParseException("Invalid value for alignment"); //$NON-NLS-1$
2547 * Gets the value of a "base" integer attribute.
2550 * An CTF_RIGHT node.
2551 * @return The "base" value.
2552 * @throws ParseException
2554 private static int getBase(CommonTree rightNode
) throws ParseException
{
2556 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2558 if (isUnaryInteger(firstChild
)) {
2559 if (rightNode
.getChildCount() > 1) {
2560 throw new ParseException("invalid base value"); //$NON-NLS-1$
2563 long intval
= parseUnaryInteger(firstChild
);
2564 if ((intval
== INTEGER_BASE_2
) || (intval
== INTEGER_BASE_8
) || (intval
== INTEGER_BASE_10
)
2565 || (intval
== INTEGER_BASE_16
)) {
2566 return (int) intval
;
2568 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2569 } else if (isUnaryString(firstChild
)) {
2570 switch (concatenateUnaryStrings(rightNode
.getChildren())) {
2571 case MetadataStrings
.DECIMAL
:
2572 case MetadataStrings
.DEC
:
2573 case MetadataStrings
.DEC_CTE
:
2574 case MetadataStrings
.INT_MOD
:
2575 case MetadataStrings
.UNSIGNED_CTE
:
2576 return INTEGER_BASE_10
;
2577 case MetadataStrings
.HEXADECIMAL
:
2578 case MetadataStrings
.HEX
:
2579 case MetadataStrings
.X
:
2580 case MetadataStrings
.X2
:
2581 case MetadataStrings
.POINTER
:
2582 return INTEGER_BASE_16
;
2583 case MetadataStrings
.OCT
:
2584 case MetadataStrings
.OCTAL
:
2585 case MetadataStrings
.OCTAL_CTE
:
2586 return INTEGER_BASE_8
;
2587 case MetadataStrings
.BIN
:
2588 case MetadataStrings
.BINARY
:
2589 return INTEGER_BASE_2
;
2591 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2594 throw new ParseException("invalid value for base"); //$NON-NLS-1$
2599 * Gets the value of an "encoding" integer attribute.
2603 * @return The "encoding" value.
2604 * @throws ParseException
2607 private static Encoding
getEncoding(CommonTree rightNode
)
2608 throws ParseException
{
2610 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2612 if (isUnaryString(firstChild
)) {
2613 String strval
= concatenateUnaryStrings(rightNode
.getChildren());
2615 if (strval
.equals(MetadataStrings
.UTF8
)) {
2616 return Encoding
.UTF8
;
2617 } else if (strval
.equals(MetadataStrings
.ASCII
)) {
2618 return Encoding
.ASCII
;
2619 } else if (strval
.equals(MetadataStrings
.NONE
)) {
2620 return Encoding
.NONE
;
2622 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2625 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2628 private static long getStreamID(CommonTree rightNode
) throws ParseException
{
2630 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2632 if (isUnaryInteger(firstChild
)) {
2633 if (rightNode
.getChildCount() > 1) {
2634 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2637 long intval
= parseUnaryInteger(firstChild
);
2641 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2644 private static String
getEventName(CommonTree rightNode
)
2645 throws ParseException
{
2647 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2649 if (isAnyUnaryString(firstChild
)) {
2650 String str
= concatenateUnaryStrings(rightNode
.getChildren());
2654 throw new ParseException("invalid value for event name"); //$NON-NLS-1$
2657 private static long getEventID(CommonTree rightNode
) throws ParseException
{
2659 CommonTree firstChild
= (CommonTree
) rightNode
.getChild(0);
2661 if (isUnaryInteger(firstChild
)) {
2662 if (rightNode
.getChildCount() > 1) {
2663 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2666 long intval
= parseUnaryInteger(firstChild
);
2667 if (intval
> Integer
.MAX_VALUE
) {
2668 throw new ParseException("Event id larger than int.maxvalue, something is amiss"); //$NON-NLS-1$
2672 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2676 * Concatenates a list of unary strings separated by arrows (->) or dots.
2679 * A list, first element being an unary string, subsequent
2680 * elements being ARROW or DOT nodes with unary strings as child.
2681 * @return The string representation of the unary string chain.
2683 private static String
concatenateUnaryStrings(List
<CommonTree
> strings
) {
2685 StringBuilder sb
= new StringBuilder();
2687 CommonTree first
= strings
.get(0);
2688 sb
.append(parseUnaryString(first
));
2690 boolean isFirst
= true;
2692 for (CommonTree ref
: strings
) {
2698 CommonTree id
= (CommonTree
) ref
.getChild(0);
2700 if (ref
.getType() == CTFParser
.ARROW
) {
2701 sb
.append("->"); //$NON-NLS-1$
2706 sb
.append(parseUnaryString(id
));
2709 return sb
.toString();
2713 * Throws a ParseException stating that the parent-child relation between
2714 * the given node and its parent is not valid. It means that the shape of
2715 * the AST is unexpected.
2718 * The invalid child node.
2719 * @return ParseException with details
2721 private static ParseException
childTypeError(CommonTree child
) {
2722 CommonTree parent
= (CommonTree
) child
.getParent();
2723 String error
= "Parent " + CTFParser
.tokenNames
[parent
.getType()] //$NON-NLS-1$
2724 + " can't have a child of type " //$NON-NLS-1$
2725 + CTFParser
.tokenNames
[child
.getType()] + "."; //$NON-NLS-1$
2727 return new ParseException(error
);
2730 // ------------------------------------------------------------------------
2732 // ------------------------------------------------------------------------
2735 * Adds a new declaration scope on the top of the scope stack.
2737 private void pushScope() {
2738 fScope
= new DeclarationScope(fScope
);
2742 * Removes the top declaration scope from the scope stack.
2744 private void popScope() {
2745 fScope
= fScope
.getParentScope();
2749 * Returns the current declaration scope.
2751 * @return The current declaration scope.
2753 private DeclarationScope
getCurrentScope() {