1 /*******************************************************************************
2 * Copyright (c) 2015 Ericsson
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
9 package org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
.tsdl
;
11 import static org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
.tsdl
.TsdlUtils
.childTypeError
;
12 import static org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
.tsdl
.TsdlUtils
.concatenateUnaryStrings
;
13 import static org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
.tsdl
.TsdlUtils
.isAnyUnaryString
;
14 import static org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
.tsdl
.TsdlUtils
.isUnaryInteger
;
16 import java
.util
.Collections
;
17 import java
.util
.LinkedList
;
18 import java
.util
.List
;
20 import org
.antlr
.runtime
.tree
.CommonTree
;
21 import org
.eclipse
.jdt
.annotation
.NonNull
;
22 import org
.eclipse
.jdt
.annotation
.NonNullByDefault
;
23 import org
.eclipse
.tracecompass
.ctf
.core
.event
.metadata
.DeclarationScope
;
24 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IDeclaration
;
25 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IntegerDeclaration
;
26 import org
.eclipse
.tracecompass
.ctf
.core
.trace
.CTFTrace
;
27 import org
.eclipse
.tracecompass
.ctf
.parser
.CTFParser
;
28 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
.AbstractScopedCommonTreeParser
;
29 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
.ParseException
;
30 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
.tsdl
.event
.EventScopeParser
;
31 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
.tsdl
.stream
.StreamScopeParser
;
32 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
.tsdl
.trace
.TraceScopeParser
;
33 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.ArrayDeclaration
;
34 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.SequenceDeclaration
;
37 * A type declarator parser
39 * @author Matthew Khouzam
42 public class TypeDeclaratorParser
extends AbstractScopedCommonTreeParser
{
45 * The parameter object for type declarator parsers
47 * @author Matthew Khouzam
51 public static final class Param
implements ICommonTreeParserParameter
{
52 private final DeclarationScope fDeclarationScope
;
53 private final CommonTree fListNode
;
54 private final StringBuilder fBuilder
;
55 private final CTFTrace fTrace
;
58 * Parameter constructor
67 * the string builder to populate
69 public Param(CTFTrace trace
, CommonTree listNode
, DeclarationScope scope
, StringBuilder builder
) {
72 fDeclarationScope
= scope
;
80 public final static TypeDeclaratorParser INSTANCE
= new TypeDeclaratorParser();
82 private TypeDeclaratorParser() {
86 * Parses a pair type declarator / type specifier list and returns the
87 * corresponding declaration. If it is present, it also writes the
88 * identifier of the declarator in the given {@link StringBuilder}.
90 * @param typeDeclarator
91 * A TYPE_DECLARATOR node.
93 * the parameter object
94 * @return The corresponding declaration.
95 * @throws ParseException
96 * If there is an error finding or creating the declaration.
99 public IDeclaration
parse(CommonTree typeDeclarator
, ICommonTreeParserParameter param
) throws ParseException
{
100 if (!(param
instanceof Param
)) {
101 throw new IllegalArgumentException("Param must be a " + Param
.class.getCanonicalName()); //$NON-NLS-1$
103 DeclarationScope scope
= ((Param
) param
).fDeclarationScope
;
104 CTFTrace trace
= ((Param
) param
).fTrace
;
105 CommonTree typeSpecifierList
= ((Param
) param
).fListNode
;
107 IDeclaration declaration
= null;
108 List
<CommonTree
> children
= null;
109 List
<@NonNull CommonTree
> pointers
= new LinkedList
<>();
110 List
<CommonTree
> lengths
= new LinkedList
<>();
111 CommonTree identifier
= null;
113 /* Separate the tokens by type */
114 if (typeDeclarator
!= null) {
115 children
= typeDeclarator
.getChildren();
116 for (CommonTree child
: children
) {
118 switch (child
.getType()) {
119 case CTFParser
.POINTER
:
122 case CTFParser
.IDENTIFIER
:
125 case CTFParser
.LENGTH
:
129 throw childTypeError(child
);
136 * Parse the type specifier list, which is the "base" type. For example,
137 * it would be int in int a[3][len].
139 declaration
= TypeSpecifierListParser
.INSTANCE
.parse(typeSpecifierList
, new TypeSpecifierListParser
.Param(trace
, pointers
, identifier
, scope
));
142 * Each length subscript means that we must create a nested array or
143 * sequence. For example, int a[3][len] means that we have an array of 3
144 * (sequences of length 'len' of (int)).
146 if (!lengths
.isEmpty()) {
147 /* We begin at the end */
148 Collections
.reverse(lengths
);
150 for (CommonTree length
: lengths
) {
152 * By looking at the first expression, we can determine whether
153 * it is an array or a sequence.
155 List
<CommonTree
> lengthChildren
= length
.getChildren();
157 CommonTree first
= lengthChildren
.get(0);
158 if (isUnaryInteger(first
)) {
160 int arrayLength
= UnaryIntegerParser
.INSTANCE
.parse(first
, null).intValue();
162 if (arrayLength
< 1) {
163 throw new ParseException("Array length is negative"); //$NON-NLS-1$
166 /* Create the array declaration. */
167 declaration
= new ArrayDeclaration(arrayLength
, declaration
);
168 } else if (isAnyUnaryString(first
)) {
170 String lengthName
= concatenateUnaryStrings(lengthChildren
);
172 /* check that lengthName was declared */
173 if (isSignedIntegerField(lengthName
, scope
)) {
174 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
176 /* Create the sequence declaration. */
177 declaration
= new SequenceDeclaration(lengthName
,
179 } else if (isTrace(first
)) {
181 String lengthName
= TraceScopeParser
.INSTANCE
.parse(null, new TraceScopeParser
.Param(lengthChildren
));
183 /* check that lengthName was declared */
184 if (isSignedIntegerField(lengthName
, scope
)) {
185 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
187 /* Create the sequence declaration. */
188 declaration
= new SequenceDeclaration(lengthName
,
191 } else if (isStream(first
)) {
193 String lengthName
= StreamScopeParser
.INSTANCE
.parse(null, new StreamScopeParser
.Param(lengthChildren
));
195 /* check that lengthName was declared */
196 if (isSignedIntegerField(lengthName
, scope
)) {
197 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
199 /* Create the sequence declaration. */
200 declaration
= new SequenceDeclaration(lengthName
,
202 } else if (isEvent(first
)) {
204 String lengthName
= EventScopeParser
.INSTANCE
.parse(null, new EventScopeParser
.Param(lengthChildren
));
206 /* check that lengthName was declared */
207 if (isSignedIntegerField(lengthName
, scope
)) {
208 throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$
210 /* Create the sequence declaration. */
211 declaration
= new SequenceDeclaration(lengthName
,
214 throw childTypeError(first
);
219 if (identifier
!= null) {
220 final String text
= identifier
.getText();
222 throw new ParseException("Cannot have unidentified declarator"); //$NON-NLS-1$
224 ((Param
) param
).fBuilder
.append(text
);
225 registerType(declaration
, text
, scope
);
231 private static boolean isSignedIntegerField(String lengthName
, DeclarationScope scope
) throws ParseException
{
232 IDeclaration decl
= scope
.lookupIdentifierRecursive(lengthName
);
233 if (decl
instanceof IntegerDeclaration
) {
234 return ((IntegerDeclaration
) decl
).isSigned();
236 throw new ParseException("Is not an integer: " + lengthName
); //$NON-NLS-1$
240 private static boolean isEvent(CommonTree first
) {
241 return first
.getType() == CTFParser
.EVENT
;
244 private static boolean isStream(CommonTree first
) {
245 return first
.getType() == CTFParser
.STREAM
;
248 private static boolean isTrace(CommonTree first
) {
249 return first
.getType() == CTFParser
.TRACE
;