Commit | Line | Data |
---|---|---|
866e5b51 | 1 | /******************************************************************************* |
3ba65808 | 2 | * Copyright (c) 2011, 2015 Ericsson, Ecole Polytechnique de Montreal and others |
866e5b51 FC |
3 | * |
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 | |
8 | * | |
4311ac8b MAL |
9 | * Contributors: |
10 | * Matthew Khouzam - Initial Design and Grammar | |
11 | * Francis Giraldeau - Initial API and implementation | |
12 | * Simon Marchi - Initial API and implementation | |
866e5b51 FC |
13 | *******************************************************************************/ |
14 | ||
f357bcd4 | 15 | package org.eclipse.tracecompass.internal.ctf.core.event.metadata; |
866e5b51 | 16 | |
4311ac8b | 17 | import java.math.BigInteger; |
866e5b51 FC |
18 | import java.nio.ByteOrder; |
19 | import java.util.ArrayList; | |
20 | import java.util.Collections; | |
816fde81 | 21 | import java.util.HashSet; |
866e5b51 FC |
22 | import java.util.LinkedList; |
23 | import java.util.List; | |
816fde81 | 24 | import java.util.Set; |
866e5b51 FC |
25 | import java.util.UUID; |
26 | ||
27 | import org.antlr.runtime.tree.CommonTree; | |
4311ac8b | 28 | import org.eclipse.core.runtime.IStatus; |
a4fa4e36 | 29 | import org.eclipse.jdt.annotation.NonNull; |
3ba65808 | 30 | import org.eclipse.jdt.annotation.Nullable; |
8d90cd62 | 31 | import org.eclipse.tracecompass.ctf.core.CTFStrings; |
f357bcd4 | 32 | import org.eclipse.tracecompass.ctf.core.event.CTFClock; |
c8891db9 | 33 | import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope; |
f357bcd4 AM |
34 | import org.eclipse.tracecompass.ctf.core.event.types.Encoding; |
35 | import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration; | |
36 | import org.eclipse.tracecompass.ctf.core.event.types.FloatDeclaration; | |
37 | import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration; | |
38 | import org.eclipse.tracecompass.ctf.core.event.types.IEventHeaderDeclaration; | |
39 | import org.eclipse.tracecompass.ctf.core.event.types.IntegerDeclaration; | |
40 | import org.eclipse.tracecompass.ctf.core.event.types.StringDeclaration; | |
41 | import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration; | |
42 | import org.eclipse.tracecompass.ctf.core.event.types.VariantDeclaration; | |
43 | import org.eclipse.tracecompass.ctf.core.trace.CTFStream; | |
44 | import org.eclipse.tracecompass.ctf.core.trace.CTFTrace; | |
45 | import org.eclipse.tracecompass.ctf.parser.CTFParser; | |
46 | import org.eclipse.tracecompass.internal.ctf.core.Activator; | |
47 | import org.eclipse.tracecompass.internal.ctf.core.event.EventDeclaration; | |
48 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.exceptions.ParseException; | |
49 | import org.eclipse.tracecompass.internal.ctf.core.event.types.ArrayDeclaration; | |
50 | import org.eclipse.tracecompass.internal.ctf.core.event.types.SequenceDeclaration; | |
51 | import org.eclipse.tracecompass.internal.ctf.core.event.types.StructDeclarationFlattener; | |
52 | import org.eclipse.tracecompass.internal.ctf.core.event.types.composite.EventHeaderCompactDeclaration; | |
53 | import org.eclipse.tracecompass.internal.ctf.core.event.types.composite.EventHeaderLargeDeclaration; | |
866e5b51 | 54 | |
52f81ef7 MK |
55 | import com.google.common.collect.Iterables; |
56 | ||
866e5b51 | 57 | /** |
251274dd | 58 | * IOStructGen |
866e5b51 | 59 | */ |
866e5b51 FC |
60 | public class IOStructGen { |
61 | ||
62 | // ------------------------------------------------------------------------ | |
63 | // Attributes | |
64 | // ------------------------------------------------------------------------ | |
65 | ||
62c21477 MK |
66 | private static final @NonNull String MAP = "map"; //$NON-NLS-1$ |
67 | private static final @NonNull String ENCODING = "encoding"; //$NON-NLS-1$ | |
68 | private static final @NonNull String BASE = "base"; //$NON-NLS-1$ | |
69 | private static final @NonNull String SIZE = "size"; //$NON-NLS-1$ | |
70 | private static final @NonNull String SIGNED = "signed"; //$NON-NLS-1$ | |
71 | private static final @NonNull String LINE = "line"; //$NON-NLS-1$ | |
72 | private static final @NonNull String FILE = "file"; //$NON-NLS-1$ | |
73 | private static final @NonNull String IP = "ip"; //$NON-NLS-1$ | |
74 | private static final @NonNull String FUNC = "func"; //$NON-NLS-1$ | |
75 | private static final @NonNull String NAME = "name"; //$NON-NLS-1$ | |
76 | private static final @NonNull String EMPTY_STRING = ""; //$NON-NLS-1$ | |
466f6d95 MK |
77 | private static final int INTEGER_BASE_16 = 16; |
78 | private static final int INTEGER_BASE_10 = 10; | |
79 | private static final int INTEGER_BASE_8 = 8; | |
80 | private static final int INTEGER_BASE_2 = 2; | |
b4685f09 | 81 | private static final long DEFAULT_ALIGNMENT = 1; |
466f6d95 MK |
82 | private static final int DEFAULT_FLOAT_EXPONENT = 8; |
83 | private static final int DEFAULT_FLOAT_MANTISSA = 24; | |
84 | private static final int DEFAULT_INT_BASE = 10; | |
866e5b51 FC |
85 | /** |
86 | * The trace | |
87 | */ | |
9226cfc5 MK |
88 | private final CTFTrace fTrace; |
89 | private CommonTree fTree; | |
866e5b51 FC |
90 | |
91 | /** | |
92 | * The current declaration scope. | |
93 | */ | |
3ba65808 MK |
94 | private final DeclarationScope fRoot; |
95 | private DeclarationScope fScope; | |
866e5b51 | 96 | |
58129ff7 MK |
97 | /** |
98 | * Data helpers needed for streaming | |
99 | */ | |
100 | ||
101 | private boolean fHasBeenParsed = false; | |
102 | ||
866e5b51 FC |
103 | // ------------------------------------------------------------------------ |
104 | // Constructor | |
105 | // ------------------------------------------------------------------------ | |
106 | ||
9ac2eb62 | 107 | /** |
ecb12461 | 108 | * Constructor |
be6df2d8 AM |
109 | * |
110 | * @param tree | |
111 | * the tree (ANTLR generated) with the parsed TSDL data. | |
112 | * @param trace | |
113 | * the trace containing the places to put all the read metadata | |
9ac2eb62 | 114 | */ |
866e5b51 | 115 | public IOStructGen(CommonTree tree, CTFTrace trace) { |
9226cfc5 MK |
116 | fTrace = trace; |
117 | fTree = tree; | |
8d90cd62 | 118 | fRoot = trace.getScope(); |
3ba65808 | 119 | fScope = fRoot; |
866e5b51 FC |
120 | } |
121 | ||
9ac2eb62 MK |
122 | /** |
123 | * Parse the tree and populate the trace defined in the constructor. | |
be6df2d8 | 124 | * |
9ac2eb62 | 125 | * @throws ParseException |
be6df2d8 | 126 | * If there was a problem parsing the metadata |
9ac2eb62 | 127 | */ |
866e5b51 | 128 | public void generate() throws ParseException { |
9226cfc5 | 129 | parseRoot(fTree); |
866e5b51 FC |
130 | } |
131 | ||
58129ff7 MK |
132 | /** |
133 | * Parse a partial tree and populate the trace defined in the constructor. | |
134 | * Does not check for a "trace" block as there is only one in the trace and | |
135 | * thus | |
136 | * | |
137 | * @throws ParseException | |
138 | * If there was a problem parsing the metadata | |
139 | */ | |
140 | public void generateFragment() throws ParseException { | |
9226cfc5 | 141 | parseIncompleteRoot(fTree); |
58129ff7 MK |
142 | } |
143 | ||
866e5b51 FC |
144 | // ------------------------------------------------------------------------ |
145 | // Operations | |
146 | // ------------------------------------------------------------------------ | |
147 | ||
58129ff7 MK |
148 | /** |
149 | * Sets a new tree to parse | |
150 | * | |
151 | * @param newTree | |
152 | * the new tree to parse | |
153 | */ | |
154 | public void setTree(CommonTree newTree) { | |
9226cfc5 | 155 | fTree = newTree; |
58129ff7 MK |
156 | } |
157 | ||
866e5b51 FC |
158 | /** |
159 | * Parse the root node. | |
160 | * | |
161 | * @param root | |
162 | * A ROOT node. | |
163 | * @throws ParseException | |
164 | */ | |
165 | private void parseRoot(CommonTree root) throws ParseException { | |
866e5b51 FC |
166 | |
167 | List<CommonTree> children = root.getChildren(); | |
866e5b51 FC |
168 | |
169 | CommonTree traceNode = null; | |
52f81ef7 | 170 | boolean hasStreams = false; |
3de23137 | 171 | List<CommonTree> events = new ArrayList<>(); |
3ba65808 | 172 | resetScope(); |
466f6d95 MK |
173 | for (CommonTree child : children) { |
174 | final int type = child.getType(); | |
175 | switch (type) { | |
176 | case CTFParser.DECLARATION: | |
52f81ef7 | 177 | parseRootDeclaration(child); |
466f6d95 MK |
178 | break; |
179 | case CTFParser.TRACE: | |
180 | if (traceNode != null) { | |
181 | throw new ParseException("Only one trace block is allowed"); //$NON-NLS-1$ | |
866e5b51 | 182 | } |
466f6d95 | 183 | traceNode = child; |
52f81ef7 | 184 | parseTrace(traceNode); |
466f6d95 MK |
185 | break; |
186 | case CTFParser.STREAM: | |
52f81ef7 MK |
187 | parseStream(child); |
188 | hasStreams = true; | |
466f6d95 MK |
189 | break; |
190 | case CTFParser.EVENT: | |
191 | events.add(child); | |
192 | break; | |
193 | case CTFParser.CLOCK: | |
52f81ef7 | 194 | parseClock(child); |
466f6d95 MK |
195 | break; |
196 | case CTFParser.ENV: | |
52f81ef7 | 197 | parseEnvironment(child); |
466f6d95 MK |
198 | break; |
199 | case CTFParser.CALLSITE: | |
52f81ef7 | 200 | parseCallsite(child); |
466f6d95 MK |
201 | break; |
202 | default: | |
4ed7d9c1 | 203 | throw childTypeError(child); |
866e5b51 | 204 | } |
466f6d95 | 205 | } |
466f6d95 MK |
206 | if (traceNode == null) { |
207 | throw new ParseException("Missing trace block"); //$NON-NLS-1$ | |
208 | } | |
52f81ef7 MK |
209 | parseEvents(events, hasStreams); |
210 | popScope(); | |
211 | fHasBeenParsed = true; | |
212 | } | |
866e5b51 | 213 | |
52f81ef7 MK |
214 | private void parseEvents(List<CommonTree> events, boolean hasStreams) throws ParseException { |
215 | if (!hasStreams && !events.isEmpty()) { | |
466f6d95 MK |
216 | /* Add an empty stream that will have a null id */ |
217 | fTrace.addStream(new CTFStream(fTrace)); | |
218 | } | |
466f6d95 MK |
219 | for (CommonTree event : events) { |
220 | parseEvent(event); | |
866e5b51 | 221 | } |
58129ff7 MK |
222 | } |
223 | ||
224 | private void parseIncompleteRoot(CommonTree root) throws ParseException { | |
466f6d95 | 225 | if (!fHasBeenParsed) { |
58129ff7 MK |
226 | throw new ParseException("You need to run generate first"); //$NON-NLS-1$ |
227 | } | |
52f81ef7 | 228 | List<CommonTree> children = root.getChildren(); |
58129ff7 | 229 | List<CommonTree> events = new ArrayList<>(); |
3ba65808 | 230 | resetScope(); |
58129ff7 MK |
231 | for (CommonTree child : children) { |
232 | final int type = child.getType(); | |
233 | switch (type) { | |
234 | case CTFParser.DECLARATION: | |
52f81ef7 | 235 | parseRootDeclaration(child); |
58129ff7 MK |
236 | break; |
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: | |
52f81ef7 | 240 | parseStream(child); |
58129ff7 MK |
241 | break; |
242 | case CTFParser.EVENT: | |
243 | events.add(child); | |
244 | break; | |
245 | case CTFParser.CLOCK: | |
52f81ef7 | 246 | parseClock(child); |
58129ff7 MK |
247 | break; |
248 | case CTFParser.ENV: | |
52f81ef7 | 249 | parseEnvironment(child); |
58129ff7 MK |
250 | break; |
251 | case CTFParser.CALLSITE: | |
52f81ef7 | 252 | parseCallsite(child); |
58129ff7 MK |
253 | break; |
254 | default: | |
4ed7d9c1 | 255 | throw childTypeError(child); |
58129ff7 MK |
256 | } |
257 | } | |
52f81ef7 | 258 | parseEvents(events, !Iterables.isEmpty(fTrace.getStreams())); |
58129ff7 | 259 | popScope(); |
866e5b51 FC |
260 | } |
261 | ||
3ba65808 MK |
262 | private void resetScope() { |
263 | fScope = fRoot; | |
264 | } | |
265 | ||
4c9d2941 MK |
266 | private void parseCallsite(CommonTree callsite) { |
267 | ||
268 | List<CommonTree> children = callsite.getChildren(); | |
269 | String name = null; | |
0594c61c AM |
270 | String funcName = null; |
271 | long lineNumber = -1; | |
4c9d2941 | 272 | long ip = -1; |
0594c61c | 273 | String fileName = null; |
4c9d2941 MK |
274 | |
275 | for (CommonTree child : children) { | |
276 | String left; | |
ecb12461 | 277 | /* this is a regex to find the leading and trailing quotes */ |
4c9d2941 | 278 | final String regex = "^\"|\"$"; //$NON-NLS-1$ |
2c053b6e MK |
279 | /* |
280 | * this is to replace the previous quotes with nothing... | |
281 | * effectively deleting them | |
282 | */ | |
62c21477 | 283 | final String nullString = EMPTY_STRING; |
4c9d2941 | 284 | left = child.getChild(0).getChild(0).getChild(0).getText(); |
62c21477 | 285 | if (left.equals(NAME)) { |
4c9d2941 | 286 | name = child.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex, nullString); |
62c21477 | 287 | } else if (left.equals(FUNC)) { |
0594c61c | 288 | funcName = child.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex, nullString); |
62c21477 | 289 | } else if (left.equals(IP)) { |
c30da2fa | 290 | ip = Long.decode(child.getChild(1).getChild(0).getChild(0).getText()); |
62c21477 | 291 | } else if (left.equals(FILE)) { |
0594c61c | 292 | fileName = child.getChild(1).getChild(0).getChild(0).getText().replaceAll(regex, nullString); |
62c21477 | 293 | } else if (left.equals(LINE)) { |
0594c61c | 294 | lineNumber = Long.parseLong(child.getChild(1).getChild(0).getChild(0).getText()); |
4c9d2941 MK |
295 | } |
296 | } | |
9226cfc5 | 297 | fTrace.addCallsite(name, funcName, ip, fileName, lineNumber); |
4c9d2941 MK |
298 | } |
299 | ||
866e5b51 FC |
300 | private void parseEnvironment(CommonTree environment) { |
301 | List<CommonTree> children = environment.getChildren(); | |
302 | for (CommonTree child : children) { | |
303 | String left; | |
304 | String right; | |
305 | left = child.getChild(0).getChild(0).getChild(0).getText(); | |
306 | right = child.getChild(1).getChild(0).getChild(0).getText(); | |
9226cfc5 | 307 | fTrace.addEnvironmentVar(left, right); |
866e5b51 FC |
308 | } |
309 | } | |
310 | ||
466f6d95 | 311 | private void parseClock(CommonTree clock) throws ParseException { |
866e5b51 FC |
312 | List<CommonTree> children = clock.getChildren(); |
313 | CTFClock ctfClock = new CTFClock(); | |
314 | for (CommonTree child : children) { | |
72dbc4ac | 315 | final String key = child.getChild(0).getChild(0).getChild(0).getText(); |
866e5b51 FC |
316 | final CommonTree value = (CommonTree) child.getChild(1).getChild(0).getChild(0); |
317 | final int type = value.getType(); | |
d0b5ef0d | 318 | final String text = value.getText(); |
866e5b51 FC |
319 | switch (type) { |
320 | case CTFParser.INTEGER: | |
321 | case CTFParser.DECIMAL_LITERAL: | |
284fdee8 | 322 | /* |
32ede2ec MK |
323 | * Not a pretty hack, this is to make sure that there is no |
324 | * number overflow due to 63 bit integers. The offset should | |
325 | * only really be an issue in the year 2262. the tracer in C/ASM | |
326 | * can write an offset in an unsigned 64 bit long. In java, the | |
327 | * last bit, being set to 1 will be read as a negative number, | |
328 | * but since it is too big a positive it will throw an | |
329 | * exception. this will happen in 2^63 ns from 1970. Therefore | |
330 | * 293 years from 1970 | |
284fdee8 | 331 | */ |
866e5b51 | 332 | Long numValue; |
32ede2ec | 333 | try { |
d0b5ef0d MK |
334 | numValue = Long.parseLong(text); |
335 | } catch (NumberFormatException e) { | |
336 | throw new ParseException("Number conversion issue with " + text, e); //$NON-NLS-1$ | |
866e5b51 FC |
337 | } |
338 | ctfClock.addAttribute(key, numValue); | |
339 | break; | |
340 | default: | |
d0b5ef0d | 341 | ctfClock.addAttribute(key, text); |
866e5b51 FC |
342 | } |
343 | ||
344 | } | |
0594c61c | 345 | String nameValue = ctfClock.getName(); |
9226cfc5 | 346 | fTrace.addClock(nameValue, ctfClock); |
866e5b51 FC |
347 | } |
348 | ||
349 | private void parseTrace(CommonTree traceNode) throws ParseException { | |
866e5b51 FC |
350 | |
351 | List<CommonTree> children = traceNode.getChildren(); | |
352 | if (children == null) { | |
353 | throw new ParseException("Trace block is empty"); //$NON-NLS-1$ | |
354 | } | |
355 | ||
8d90cd62 | 356 | resetScope(); |
866e5b51 FC |
357 | |
358 | for (CommonTree child : children) { | |
359 | switch (child.getType()) { | |
360 | case CTFParser.TYPEALIAS: | |
361 | parseTypealias(child); | |
362 | break; | |
363 | case CTFParser.TYPEDEF: | |
364 | parseTypedef(child); | |
365 | break; | |
366 | case CTFParser.CTF_EXPRESSION_TYPE: | |
367 | case CTFParser.CTF_EXPRESSION_VAL: | |
368 | parseTraceDeclaration(child); | |
369 | break; | |
370 | default: | |
4ed7d9c1 | 371 | throw childTypeError(child); |
866e5b51 FC |
372 | } |
373 | } | |
374 | ||
375 | /* | |
376 | * If trace byte order was not specified and not using packet based | |
377 | * metadata | |
378 | */ | |
9226cfc5 | 379 | if (fTrace.getByteOrder() == null) { |
866e5b51 FC |
380 | throw new ParseException("Trace byte order not set"); //$NON-NLS-1$ |
381 | } | |
866e5b51 FC |
382 | } |
383 | ||
384 | private void parseTraceDeclaration(CommonTree traceDecl) | |
385 | throws ParseException { | |
866e5b51 FC |
386 | |
387 | /* There should be a left and right */ | |
866e5b51 FC |
388 | |
389 | CommonTree leftNode = (CommonTree) traceDecl.getChild(0); | |
866e5b51 | 390 | CommonTree rightNode = (CommonTree) traceDecl.getChild(1); |
866e5b51 FC |
391 | |
392 | List<CommonTree> leftStrings = leftNode.getChildren(); | |
866e5b51 | 393 | |
4311ac8b | 394 | if (!isAnyUnaryString(leftStrings.get(0))) { |
2c053b6e | 395 | throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$ |
866e5b51 FC |
396 | } |
397 | ||
398 | String left = concatenateUnaryStrings(leftStrings); | |
399 | ||
fafc36a7 | 400 | if (left.equals(MetadataStrings.MAJOR)) { |
9226cfc5 | 401 | if (fTrace.majorIsSet()) { |
866e5b51 FC |
402 | throw new ParseException("major is already set"); //$NON-NLS-1$ |
403 | } | |
404 | ||
9226cfc5 | 405 | fTrace.setMajor(getMajorOrMinor(rightNode)); |
fafc36a7 | 406 | } else if (left.equals(MetadataStrings.MINOR)) { |
9226cfc5 | 407 | if (fTrace.minorIsSet()) { |
866e5b51 FC |
408 | throw new ParseException("minor is already set"); //$NON-NLS-1$ |
409 | } | |
410 | ||
9226cfc5 | 411 | fTrace.setMinor(getMajorOrMinor(rightNode)); |
fafc36a7 | 412 | } else if (left.equals(MetadataStrings.UUID_STRING)) { |
866e5b51 FC |
413 | UUID uuid = getUUID(rightNode); |
414 | ||
415 | /* | |
416 | * If uuid was already set by a metadata packet, compare it to see | |
417 | * if it matches | |
418 | */ | |
9226cfc5 MK |
419 | if (fTrace.uuidIsSet()) { |
420 | if (fTrace.getUUID().compareTo(uuid) != 0) { | |
866e5b51 | 421 | throw new ParseException("UUID mismatch. Packet says " //$NON-NLS-1$ |
9226cfc5 | 422 | + fTrace.getUUID() + " but metadata says " + uuid); //$NON-NLS-1$ |
866e5b51 FC |
423 | } |
424 | } else { | |
9226cfc5 | 425 | fTrace.setUUID(uuid); |
866e5b51 FC |
426 | } |
427 | ||
fafc36a7 | 428 | } else if (left.equals(MetadataStrings.BYTE_ORDER)) { |
866e5b51 FC |
429 | ByteOrder byteOrder = getByteOrder(rightNode); |
430 | ||
431 | /* | |
432 | * If byte order was already set by a metadata packet, compare it to | |
433 | * see if it matches | |
434 | */ | |
9226cfc5 MK |
435 | if (fTrace.getByteOrder() != null) { |
436 | if (fTrace.getByteOrder() != byteOrder) { | |
866e5b51 FC |
437 | throw new ParseException( |
438 | "Endianness mismatch. Magic number says " //$NON-NLS-1$ | |
9226cfc5 | 439 | + fTrace.getByteOrder() |
866e5b51 FC |
440 | + " but metadata says " + byteOrder); //$NON-NLS-1$ |
441 | } | |
442 | } else { | |
9226cfc5 | 443 | fTrace.setByteOrder(byteOrder); |
72dbc4ac | 444 | |
8d90cd62 MK |
445 | final DeclarationScope currentScope = getCurrentScope(); |
446 | for (String type : currentScope.getTypeNames()) { | |
447 | IDeclaration d = currentScope.lookupType(type); | |
72dbc4ac | 448 | if (d instanceof IntegerDeclaration) { |
8d90cd62 | 449 | addByteOrder(byteOrder, currentScope, type, (IntegerDeclaration) d); |
72dbc4ac | 450 | } else if (d instanceof StructDeclaration) { |
8d90cd62 | 451 | setAlign(currentScope, (StructDeclaration) d, byteOrder); |
72dbc4ac MK |
452 | } |
453 | } | |
866e5b51 | 454 | } |
fafc36a7 | 455 | } else if (left.equals(MetadataStrings.PACKET_HEADER)) { |
9226cfc5 | 456 | if (fTrace.packetHeaderIsSet()) { |
866e5b51 FC |
457 | throw new ParseException("packet.header already defined"); //$NON-NLS-1$ |
458 | } | |
459 | ||
460 | CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0); | |
461 | ||
462 | if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) { | |
2c053b6e | 463 | throw new ParseException("packet.header expects a type specifier"); //$NON-NLS-1$ |
866e5b51 FC |
464 | } |
465 | ||
94c255ef | 466 | IDeclaration packetHeaderDecl = parseTypeSpecifierList(typeSpecifier); |
866e5b51 FC |
467 | |
468 | if (!(packetHeaderDecl instanceof StructDeclaration)) { | |
469 | throw new ParseException("packet.header expects a struct"); //$NON-NLS-1$ | |
470 | } | |
471 | ||
9226cfc5 | 472 | fTrace.setPacketHeader((StructDeclaration) packetHeaderDecl); |
866e5b51 | 473 | } else { |
4311ac8b | 474 | Activator.log(IStatus.WARNING, Messages.IOStructGen_UnknownTraceAttributeWarning + " " + left); //$NON-NLS-1$ |
866e5b51 FC |
475 | } |
476 | } | |
477 | ||
72dbc4ac MK |
478 | private static void addByteOrder(ByteOrder byteOrder, |
479 | final DeclarationScope parentScope, String name, | |
480 | IntegerDeclaration decl) throws ParseException { | |
481 | ||
a4fa4e36 | 482 | if (decl.getByteOrder() != byteOrder) { |
72dbc4ac | 483 | IntegerDeclaration newI; |
a4fa4e36 | 484 | newI = IntegerDeclaration.createDeclaration(decl.getLength(), decl.isSigned(), |
72dbc4ac MK |
485 | decl.getBase(), byteOrder, decl.getEncoding(), |
486 | decl.getClock(), decl.getAlignment()); | |
487 | parentScope.replaceType(name, newI); | |
488 | } | |
489 | } | |
490 | ||
491 | private void setAlign(DeclarationScope parentScope, StructDeclaration sd, | |
492 | ByteOrder byteOrder) throws ParseException { | |
493 | ||
494 | for (String s : sd.getFieldsList()) { | |
2db699c2 | 495 | IDeclaration d = sd.getField(s); |
72dbc4ac MK |
496 | |
497 | if (d instanceof StructDeclaration) { | |
498 | setAlign(parentScope, (StructDeclaration) d, byteOrder); | |
499 | ||
500 | } else if (d instanceof VariantDeclaration) { | |
501 | setAlign(parentScope, (VariantDeclaration) d, byteOrder); | |
72dbc4ac MK |
502 | } else if (d instanceof IntegerDeclaration) { |
503 | IntegerDeclaration decl = (IntegerDeclaration) d; | |
a4fa4e36 | 504 | if (decl.getByteOrder() != byteOrder) { |
72dbc4ac | 505 | IntegerDeclaration newI; |
a4fa4e36 | 506 | newI = IntegerDeclaration.createDeclaration(decl.getLength(), |
72dbc4ac MK |
507 | decl.isSigned(), decl.getBase(), byteOrder, |
508 | decl.getEncoding(), decl.getClock(), | |
509 | decl.getAlignment()); | |
510 | sd.getFields().put(s, newI); | |
511 | } | |
512 | } | |
513 | } | |
514 | } | |
515 | ||
516 | private void setAlign(DeclarationScope parentScope, VariantDeclaration vd, | |
517 | ByteOrder byteOrder) throws ParseException { | |
518 | ||
519 | for (String s : vd.getFields().keySet()) { | |
520 | IDeclaration d = vd.getFields().get(s); | |
521 | ||
522 | if (d instanceof StructDeclaration) { | |
523 | setAlign(parentScope, (StructDeclaration) d, byteOrder); | |
524 | ||
525 | } else if (d instanceof IntegerDeclaration) { | |
526 | IntegerDeclaration decl = (IntegerDeclaration) d; | |
527 | IntegerDeclaration newI; | |
a4fa4e36 | 528 | newI = IntegerDeclaration.createDeclaration(decl.getLength(), |
72dbc4ac MK |
529 | decl.isSigned(), decl.getBase(), byteOrder, |
530 | decl.getEncoding(), decl.getClock(), | |
531 | decl.getAlignment()); | |
532 | vd.getFields().put(s, newI); | |
533 | } | |
534 | } | |
535 | } | |
536 | ||
866e5b51 | 537 | private void parseStream(CommonTree streamNode) throws ParseException { |
866e5b51 | 538 | |
d84419e1 | 539 | CTFStream stream = new CTFStream(fTrace); |
866e5b51 FC |
540 | |
541 | List<CommonTree> children = streamNode.getChildren(); | |
542 | if (children == null) { | |
543 | throw new ParseException("Empty stream block"); //$NON-NLS-1$ | |
544 | } | |
545 | ||
3ba65808 | 546 | pushScope(MetadataStrings.STREAM); |
866e5b51 FC |
547 | |
548 | for (CommonTree child : children) { | |
549 | switch (child.getType()) { | |
550 | case CTFParser.TYPEALIAS: | |
551 | parseTypealias(child); | |
552 | break; | |
553 | case CTFParser.TYPEDEF: | |
554 | parseTypedef(child); | |
555 | break; | |
556 | case CTFParser.CTF_EXPRESSION_TYPE: | |
557 | case CTFParser.CTF_EXPRESSION_VAL: | |
558 | parseStreamDeclaration(child, stream); | |
559 | break; | |
560 | default: | |
4ed7d9c1 | 561 | throw childTypeError(child); |
866e5b51 FC |
562 | } |
563 | } | |
564 | ||
466f6d95 MK |
565 | if (stream.isIdSet() && |
566 | (!fTrace.packetHeaderIsSet() || !fTrace.getPacketHeader().hasField(MetadataStrings.STREAM_ID))) { | |
567 | throw new ParseException("Stream has an ID, but there is no stream_id field in packet header."); //$NON-NLS-1$ | |
866e5b51 FC |
568 | } |
569 | ||
9226cfc5 | 570 | fTrace.addStream(stream); |
866e5b51 FC |
571 | |
572 | popScope(); | |
573 | } | |
574 | ||
d84419e1 | 575 | private void parseStreamDeclaration(CommonTree streamDecl, CTFStream stream) |
866e5b51 | 576 | throws ParseException { |
866e5b51 FC |
577 | |
578 | /* There should be a left and right */ | |
866e5b51 FC |
579 | |
580 | CommonTree leftNode = (CommonTree) streamDecl.getChild(0); | |
866e5b51 | 581 | CommonTree rightNode = (CommonTree) streamDecl.getChild(1); |
866e5b51 FC |
582 | |
583 | List<CommonTree> leftStrings = leftNode.getChildren(); | |
866e5b51 | 584 | |
4311ac8b | 585 | if (!isAnyUnaryString(leftStrings.get(0))) { |
2c053b6e | 586 | throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$ |
866e5b51 FC |
587 | } |
588 | ||
589 | String left = concatenateUnaryStrings(leftStrings); | |
590 | ||
fafc36a7 | 591 | if (left.equals(MetadataStrings.ID)) { |
9ac2eb62 | 592 | if (stream.isIdSet()) { |
866e5b51 FC |
593 | throw new ParseException("stream id already defined"); //$NON-NLS-1$ |
594 | } | |
595 | ||
596 | long streamID = getStreamID(rightNode); | |
597 | ||
598 | stream.setId(streamID); | |
fafc36a7 | 599 | } else if (left.equals(MetadataStrings.EVENT_HEADER)) { |
9ac2eb62 | 600 | if (stream.isEventHeaderSet()) { |
866e5b51 FC |
601 | throw new ParseException("event.header already defined"); //$NON-NLS-1$ |
602 | } | |
603 | ||
604 | CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0); | |
605 | ||
606 | if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) { | |
2c053b6e | 607 | throw new ParseException("event.header expects a type specifier"); //$NON-NLS-1$ |
866e5b51 FC |
608 | } |
609 | ||
94c255ef | 610 | IDeclaration eventHeaderDecl = parseTypeSpecifierList(typeSpecifier); |
8d90cd62 MK |
611 | DeclarationScope scope = getCurrentScope(); |
612 | DeclarationScope eventHeaderScope = scope.lookupChildRecursive(MetadataStrings.STRUCT); | |
613 | if (eventHeaderScope == null) { | |
614 | throw new ParseException("event.header scope not found"); //$NON-NLS-1$ | |
615 | } | |
616 | pushScope(MetadataStrings.EVENT); | |
617 | getCurrentScope().addChild(eventHeaderScope); | |
618 | eventHeaderScope.setName(CTFStrings.HEADER); | |
619 | popScope(); | |
6c7592e1 MK |
620 | if (eventHeaderDecl instanceof StructDeclaration) { |
621 | stream.setEventHeader((StructDeclaration) eventHeaderDecl); | |
622 | } else if (eventHeaderDecl instanceof IEventHeaderDeclaration) { | |
623 | stream.setEventHeader((IEventHeaderDeclaration) eventHeaderDecl); | |
624 | } else { | |
866e5b51 FC |
625 | throw new ParseException("event.header expects a struct"); //$NON-NLS-1$ |
626 | } | |
627 | ||
fafc36a7 | 628 | } else if (left.equals(MetadataStrings.EVENT_CONTEXT)) { |
9ac2eb62 | 629 | if (stream.isEventContextSet()) { |
866e5b51 FC |
630 | throw new ParseException("event.context already defined"); //$NON-NLS-1$ |
631 | } | |
632 | ||
633 | CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0); | |
634 | ||
635 | if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) { | |
2c053b6e | 636 | throw new ParseException("event.context expects a type specifier"); //$NON-NLS-1$ |
866e5b51 FC |
637 | } |
638 | ||
94c255ef | 639 | IDeclaration eventContextDecl = parseTypeSpecifierList(typeSpecifier); |
866e5b51 FC |
640 | |
641 | if (!(eventContextDecl instanceof StructDeclaration)) { | |
642 | throw new ParseException("event.context expects a struct"); //$NON-NLS-1$ | |
643 | } | |
644 | ||
645 | stream.setEventContext((StructDeclaration) eventContextDecl); | |
fafc36a7 | 646 | } else if (left.equals(MetadataStrings.PACKET_CONTEXT)) { |
9ac2eb62 | 647 | if (stream.isPacketContextSet()) { |
866e5b51 FC |
648 | throw new ParseException("packet.context already defined"); //$NON-NLS-1$ |
649 | } | |
650 | ||
651 | CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0); | |
652 | ||
653 | if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) { | |
2c053b6e | 654 | throw new ParseException("packet.context expects a type specifier"); //$NON-NLS-1$ |
866e5b51 FC |
655 | } |
656 | ||
94c255ef | 657 | IDeclaration packetContextDecl = parseTypeSpecifierList(typeSpecifier); |
866e5b51 FC |
658 | |
659 | if (!(packetContextDecl instanceof StructDeclaration)) { | |
660 | throw new ParseException("packet.context expects a struct"); //$NON-NLS-1$ | |
661 | } | |
662 | ||
663 | stream.setPacketContext((StructDeclaration) packetContextDecl); | |
664 | } else { | |
4311ac8b | 665 | Activator.log(IStatus.WARNING, Messages.IOStructGen_UnknownStreamAttributeWarning + " " + left); //$NON-NLS-1$ |
866e5b51 FC |
666 | } |
667 | } | |
668 | ||
669 | private void parseEvent(CommonTree eventNode) throws ParseException { | |
866e5b51 FC |
670 | |
671 | List<CommonTree> children = eventNode.getChildren(); | |
672 | if (children == null) { | |
673 | throw new ParseException("Empty event block"); //$NON-NLS-1$ | |
674 | } | |
675 | ||
676 | EventDeclaration event = new EventDeclaration(); | |
677 | ||
3ba65808 | 678 | pushScope(MetadataStrings.EVENT); |
866e5b51 FC |
679 | |
680 | for (CommonTree child : children) { | |
681 | switch (child.getType()) { | |
682 | case CTFParser.TYPEALIAS: | |
683 | parseTypealias(child); | |
684 | break; | |
685 | case CTFParser.TYPEDEF: | |
686 | parseTypedef(child); | |
687 | break; | |
688 | case CTFParser.CTF_EXPRESSION_TYPE: | |
689 | case CTFParser.CTF_EXPRESSION_VAL: | |
690 | parseEventDeclaration(child, event); | |
691 | break; | |
692 | default: | |
4ed7d9c1 | 693 | throw childTypeError(child); |
866e5b51 FC |
694 | } |
695 | } | |
696 | ||
697 | if (!event.nameIsSet()) { | |
698 | throw new ParseException("Event name not set"); //$NON-NLS-1$ | |
699 | } | |
700 | ||
701 | /* | |
702 | * If the event did not specify a stream, then the trace must be single | |
703 | * stream | |
704 | */ | |
705 | if (!event.streamIsSet()) { | |
9226cfc5 | 706 | if (fTrace.nbStreams() > 1) { |
2c053b6e | 707 | throw new ParseException("Event without stream_id with more than one stream"); //$NON-NLS-1$ |
866e5b51 FC |
708 | } |
709 | ||
710 | /* | |
711 | * If the event did not specify a stream, the only existing stream | |
712 | * must not have an id. Note: That behavior could be changed, it | |
713 | * could be possible to just get the only existing stream, whatever | |
714 | * is its id. | |
715 | */ | |
d84419e1 | 716 | CTFStream stream = fTrace.getStream(null); |
866e5b51 FC |
717 | |
718 | if (stream != null) { | |
719 | event.setStream(stream); | |
720 | } else { | |
2c053b6e | 721 | throw new ParseException("Event without stream_id, but there is no stream without id"); //$NON-NLS-1$ |
866e5b51 FC |
722 | } |
723 | } | |
724 | ||
725 | /* | |
726 | * Add the event to the stream. | |
727 | */ | |
728 | event.getStream().addEvent(event); | |
729 | ||
730 | popScope(); | |
731 | } | |
732 | ||
733 | private void parseEventDeclaration(CommonTree eventDecl, | |
734 | EventDeclaration event) throws ParseException { | |
866e5b51 FC |
735 | |
736 | /* There should be a left and right */ | |
866e5b51 FC |
737 | |
738 | CommonTree leftNode = (CommonTree) eventDecl.getChild(0); | |
866e5b51 | 739 | CommonTree rightNode = (CommonTree) eventDecl.getChild(1); |
866e5b51 FC |
740 | |
741 | List<CommonTree> leftStrings = leftNode.getChildren(); | |
866e5b51 | 742 | |
4311ac8b | 743 | if (!isAnyUnaryString(leftStrings.get(0))) { |
2c053b6e | 744 | throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$ |
866e5b51 FC |
745 | } |
746 | ||
747 | String left = concatenateUnaryStrings(leftStrings); | |
748 | ||
fafc36a7 | 749 | if (left.equals(MetadataStrings.NAME2)) { |
866e5b51 FC |
750 | if (event.nameIsSet()) { |
751 | throw new ParseException("name already defined"); //$NON-NLS-1$ | |
752 | } | |
753 | ||
754 | String name = getEventName(rightNode); | |
755 | ||
756 | event.setName(name); | |
fafc36a7 | 757 | } else if (left.equals(MetadataStrings.ID)) { |
866e5b51 FC |
758 | if (event.idIsSet()) { |
759 | throw new ParseException("id already defined"); //$NON-NLS-1$ | |
760 | } | |
761 | ||
762 | long id = getEventID(rightNode); | |
6c7592e1 MK |
763 | if (id > Integer.MAX_VALUE) { |
764 | throw new ParseException("id is greater than int.maxvalue, unsupported. id : " + id); //$NON-NLS-1$ | |
765 | } | |
766 | if (id < 0) { | |
767 | throw new ParseException("negative id, unsupported. id : " + id); //$NON-NLS-1$ | |
768 | } | |
769 | event.setId((int) id); | |
fafc36a7 | 770 | } else if (left.equals(MetadataStrings.STREAM_ID)) { |
866e5b51 FC |
771 | if (event.streamIsSet()) { |
772 | throw new ParseException("stream id already defined"); //$NON-NLS-1$ | |
773 | } | |
774 | ||
775 | long streamId = getStreamID(rightNode); | |
776 | ||
d84419e1 | 777 | CTFStream stream = fTrace.getStream(streamId); |
866e5b51 FC |
778 | |
779 | if (stream == null) { | |
780 | throw new ParseException("Stream " + streamId + " not found"); //$NON-NLS-1$ //$NON-NLS-2$ | |
781 | } | |
782 | ||
783 | event.setStream(stream); | |
fafc36a7 | 784 | } else if (left.equals(MetadataStrings.CONTEXT)) { |
866e5b51 FC |
785 | if (event.contextIsSet()) { |
786 | throw new ParseException("context already defined"); //$NON-NLS-1$ | |
787 | } | |
788 | ||
789 | CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0); | |
790 | ||
791 | if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) { | |
792 | throw new ParseException("context expects a type specifier"); //$NON-NLS-1$ | |
793 | } | |
794 | ||
94c255ef | 795 | IDeclaration contextDecl = parseTypeSpecifierList(typeSpecifier); |
866e5b51 FC |
796 | |
797 | if (!(contextDecl instanceof StructDeclaration)) { | |
798 | throw new ParseException("context expects a struct"); //$NON-NLS-1$ | |
799 | } | |
800 | ||
801 | event.setContext((StructDeclaration) contextDecl); | |
fafc36a7 | 802 | } else if (left.equals(MetadataStrings.FIELDS_STRING)) { |
866e5b51 FC |
803 | if (event.fieldsIsSet()) { |
804 | throw new ParseException("fields already defined"); //$NON-NLS-1$ | |
805 | } | |
806 | ||
807 | CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0); | |
808 | ||
809 | if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) { | |
810 | throw new ParseException("fields expects a type specifier"); //$NON-NLS-1$ | |
811 | } | |
812 | ||
13be1a8f | 813 | IDeclaration fieldsDecl; |
94c255ef | 814 | fieldsDecl = parseTypeSpecifierList(typeSpecifier); |
866e5b51 FC |
815 | |
816 | if (!(fieldsDecl instanceof StructDeclaration)) { | |
817 | throw new ParseException("fields expects a struct"); //$NON-NLS-1$ | |
818 | } | |
819 | /* | |
32ede2ec MK |
820 | * The underscores in the event names. These underscores were added |
821 | * by the LTTng tracer. | |
866e5b51 | 822 | */ |
91847dfc | 823 | final StructDeclaration fields = (StructDeclaration) fieldsDecl; |
866e5b51 | 824 | event.setFields(fields); |
fafc36a7 | 825 | } else if (left.equals(MetadataStrings.LOGLEVEL2)) { |
32ede2ec | 826 | long logLevel = parseUnaryInteger((CommonTree) rightNode.getChild(0)); |
53047a66 | 827 | event.setLogLevel(logLevel); |
866e5b51 | 828 | } else { |
8e964be1 MK |
829 | /* Custom event attribute, we'll add it to the attributes map */ |
830 | String right = parseUnaryString((CommonTree) rightNode.getChild(0)); | |
831 | event.setCustomAttribute(left, right); | |
866e5b51 FC |
832 | } |
833 | } | |
834 | ||
835 | /** | |
836 | * Parses a declaration at the root level. | |
837 | * | |
838 | * @param declaration | |
839 | * The declaration subtree. | |
840 | * @throws ParseException | |
841 | */ | |
842 | private void parseRootDeclaration(CommonTree declaration) | |
843 | throws ParseException { | |
866e5b51 FC |
844 | |
845 | List<CommonTree> children = declaration.getChildren(); | |
866e5b51 FC |
846 | |
847 | for (CommonTree child : children) { | |
848 | switch (child.getType()) { | |
849 | case CTFParser.TYPEDEF: | |
850 | parseTypedef(child); | |
851 | break; | |
852 | case CTFParser.TYPEALIAS: | |
853 | parseTypealias(child); | |
854 | break; | |
855 | case CTFParser.TYPE_SPECIFIER_LIST: | |
94c255ef | 856 | parseTypeSpecifierList(child); |
866e5b51 FC |
857 | break; |
858 | default: | |
4ed7d9c1 | 859 | throw childTypeError(child); |
866e5b51 FC |
860 | } |
861 | } | |
862 | } | |
863 | ||
864 | /** | |
865 | * Parses a typealias node. It parses the target, the alias, and registers | |
866 | * the type in the current scope. | |
867 | * | |
868 | * @param typealias | |
869 | * A TYPEALIAS node. | |
870 | * @throws ParseException | |
871 | */ | |
872 | private void parseTypealias(CommonTree typealias) throws ParseException { | |
866e5b51 FC |
873 | |
874 | List<CommonTree> children = typealias.getChildren(); | |
866e5b51 FC |
875 | |
876 | CommonTree target = null; | |
877 | CommonTree alias = null; | |
878 | ||
879 | for (CommonTree child : children) { | |
880 | switch (child.getType()) { | |
881 | case CTFParser.TYPEALIAS_TARGET: | |
866e5b51 FC |
882 | target = child; |
883 | break; | |
884 | case CTFParser.TYPEALIAS_ALIAS: | |
866e5b51 FC |
885 | alias = child; |
886 | break; | |
887 | default: | |
4ed7d9c1 | 888 | throw childTypeError(child); |
866e5b51 FC |
889 | } |
890 | } | |
891 | ||
866e5b51 FC |
892 | IDeclaration targetDeclaration = parseTypealiasTarget(target); |
893 | ||
0594c61c AM |
894 | if ((targetDeclaration instanceof VariantDeclaration) |
895 | && ((VariantDeclaration) targetDeclaration).isTagged()) { | |
896 | throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$ | |
866e5b51 FC |
897 | } |
898 | ||
899 | String aliasString = parseTypealiasAlias(alias); | |
900 | ||
901 | getCurrentScope().registerType(aliasString, targetDeclaration); | |
902 | } | |
903 | ||
904 | /** | |
905 | * Parses the target part of a typealias and gets the corresponding | |
906 | * declaration. | |
907 | * | |
908 | * @param target | |
909 | * A TYPEALIAS_TARGET node. | |
910 | * @return The corresponding declaration. | |
911 | * @throws ParseException | |
912 | */ | |
913 | private IDeclaration parseTypealiasTarget(CommonTree target) | |
914 | throws ParseException { | |
866e5b51 FC |
915 | |
916 | List<CommonTree> children = target.getChildren(); | |
866e5b51 FC |
917 | |
918 | CommonTree typeSpecifierList = null; | |
919 | CommonTree typeDeclaratorList = null; | |
920 | CommonTree typeDeclarator = null; | |
921 | StringBuilder identifierSB = new StringBuilder(); | |
922 | ||
923 | for (CommonTree child : children) { | |
924 | switch (child.getType()) { | |
925 | case CTFParser.TYPE_SPECIFIER_LIST: | |
866e5b51 FC |
926 | typeSpecifierList = child; |
927 | break; | |
928 | case CTFParser.TYPE_DECLARATOR_LIST: | |
866e5b51 FC |
929 | typeDeclaratorList = child; |
930 | break; | |
931 | default: | |
4ed7d9c1 | 932 | throw childTypeError(child); |
866e5b51 FC |
933 | } |
934 | } | |
935 | ||
866e5b51 FC |
936 | if (typeDeclaratorList != null) { |
937 | /* | |
938 | * Only allow one declarator | |
939 | * | |
940 | * eg: "typealias uint8_t *, ** := puint8_t;" is not permitted, | |
941 | * otherwise the new type puint8_t would maps to two different | |
942 | * types. | |
943 | */ | |
944 | if (typeDeclaratorList.getChildCount() != 1) { | |
2c053b6e | 945 | throw new ParseException("Only one type declarator is allowed in the typealias target"); //$NON-NLS-1$ |
866e5b51 FC |
946 | } |
947 | ||
948 | typeDeclarator = (CommonTree) typeDeclaratorList.getChild(0); | |
949 | } | |
950 | ||
951 | /* Parse the target type and get the declaration */ | |
952 | IDeclaration targetDeclaration = parseTypeDeclarator(typeDeclarator, | |
953 | typeSpecifierList, identifierSB); | |
954 | ||
955 | /* | |
956 | * We don't allow identifier in the target | |
957 | * | |
958 | * eg: "typealias uint8_t* hello := puint8_t;", the "hello" is not | |
959 | * permitted | |
960 | */ | |
961 | if (identifierSB.length() > 0) { | |
962 | throw new ParseException("Identifier (" + identifierSB.toString() //$NON-NLS-1$ | |
963 | + ") not expected in the typealias target"); //$NON-NLS-1$ | |
964 | } | |
965 | ||
966 | return targetDeclaration; | |
967 | } | |
968 | ||
969 | /** | |
970 | * Parses the alias part of a typealias. It parses the underlying specifier | |
971 | * list and declarator and creates the string representation that will be | |
972 | * used to register the type. | |
973 | * | |
974 | * @param alias | |
975 | * A TYPEALIAS_ALIAS node. | |
976 | * @return The string representation of the alias. | |
977 | * @throws ParseException | |
978 | */ | |
979 | private static String parseTypealiasAlias(CommonTree alias) | |
980 | throws ParseException { | |
866e5b51 FC |
981 | |
982 | List<CommonTree> children = alias.getChildren(); | |
866e5b51 FC |
983 | |
984 | CommonTree typeSpecifierList = null; | |
985 | CommonTree typeDeclaratorList = null; | |
986 | CommonTree typeDeclarator = null; | |
3de23137 | 987 | List<CommonTree> pointers = new LinkedList<>(); |
866e5b51 FC |
988 | |
989 | for (CommonTree child : children) { | |
990 | switch (child.getType()) { | |
991 | case CTFParser.TYPE_SPECIFIER_LIST: | |
866e5b51 FC |
992 | typeSpecifierList = child; |
993 | break; | |
994 | case CTFParser.TYPE_DECLARATOR_LIST: | |
866e5b51 FC |
995 | typeDeclaratorList = child; |
996 | break; | |
997 | default: | |
4ed7d9c1 | 998 | throw childTypeError(child); |
866e5b51 FC |
999 | } |
1000 | } | |
1001 | ||
1002 | /* If there is a type declarator list, extract the pointers */ | |
1003 | if (typeDeclaratorList != null) { | |
1004 | /* | |
1005 | * Only allow one declarator | |
1006 | * | |
1007 | * eg: "typealias uint8_t := puint8_t *, **;" is not permitted. | |
1008 | */ | |
1009 | if (typeDeclaratorList.getChildCount() != 1) { | |
2c053b6e | 1010 | throw new ParseException("Only one type declarator is allowed in the typealias alias"); //$NON-NLS-1$ |
866e5b51 FC |
1011 | } |
1012 | ||
1013 | typeDeclarator = (CommonTree) typeDeclaratorList.getChild(0); | |
1014 | ||
72dbc4ac | 1015 | List<CommonTree> typeDeclaratorChildren = typeDeclarator.getChildren(); |
866e5b51 FC |
1016 | |
1017 | for (CommonTree child : typeDeclaratorChildren) { | |
1018 | switch (child.getType()) { | |
1019 | case CTFParser.POINTER: | |
1020 | pointers.add(child); | |
1021 | break; | |
1022 | case CTFParser.IDENTIFIER: | |
1023 | throw new ParseException("Identifier (" + child.getText() //$NON-NLS-1$ | |
1024 | + ") not expected in the typealias target"); //$NON-NLS-1$ | |
866e5b51 | 1025 | default: |
4ed7d9c1 | 1026 | throw childTypeError(child); |
866e5b51 FC |
1027 | } |
1028 | } | |
1029 | } | |
1030 | ||
1031 | return createTypeDeclarationString(typeSpecifierList, pointers); | |
1032 | } | |
1033 | ||
1034 | /** | |
1035 | * Parses a typedef node. This creates and registers a new declaration for | |
1036 | * each declarator found in the typedef. | |
1037 | * | |
1038 | * @param typedef | |
1039 | * A TYPEDEF node. | |
1040 | * @throws ParseException | |
1041 | * If there is an error creating the declaration. | |
1042 | */ | |
1043 | private void parseTypedef(CommonTree typedef) throws ParseException { | |
866e5b51 | 1044 | |
72dbc4ac | 1045 | CommonTree typeDeclaratorListNode = (CommonTree) typedef.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST); |
866e5b51 | 1046 | |
72dbc4ac | 1047 | CommonTree typeSpecifierListNode = (CommonTree) typedef.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST); |
866e5b51 | 1048 | |
72dbc4ac | 1049 | List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren(); |
866e5b51 FC |
1050 | |
1051 | for (CommonTree typeDeclaratorNode : typeDeclaratorList) { | |
1052 | StringBuilder identifierSB = new StringBuilder(); | |
1053 | ||
0594c61c | 1054 | IDeclaration typeDeclaration = parseTypeDeclarator( |
866e5b51 FC |
1055 | typeDeclaratorNode, typeSpecifierListNode, identifierSB); |
1056 | ||
0594c61c | 1057 | if ((typeDeclaration instanceof VariantDeclaration) |
2c053b6e MK |
1058 | && ((VariantDeclaration) typeDeclaration).isTagged()) { |
1059 | throw new ParseException("Typealias of untagged variant is not permitted"); //$NON-NLS-1$ | |
866e5b51 FC |
1060 | } |
1061 | ||
1062 | getCurrentScope().registerType(identifierSB.toString(), | |
0594c61c | 1063 | typeDeclaration); |
866e5b51 FC |
1064 | } |
1065 | } | |
1066 | ||
1067 | /** | |
1068 | * Parses a pair type declarator / type specifier list and returns the | |
1069 | * corresponding declaration. If it is present, it also writes the | |
1070 | * identifier of the declarator in the given {@link StringBuilder}. | |
1071 | * | |
1072 | * @param typeDeclarator | |
1073 | * A TYPE_DECLARATOR node. | |
1074 | * @param typeSpecifierList | |
1075 | * A TYPE_SPECIFIER_LIST node. | |
1076 | * @param identifierSB | |
1077 | * A StringBuilder that will receive the identifier found in the | |
1078 | * declarator. | |
1079 | * @return The corresponding declaration. | |
1080 | * @throws ParseException | |
1081 | * If there is an error finding or creating the declaration. | |
1082 | */ | |
1083 | private IDeclaration parseTypeDeclarator(CommonTree typeDeclarator, | |
1084 | CommonTree typeSpecifierList, StringBuilder identifierSB) | |
3ba65808 | 1085 | throws ParseException { |
866e5b51 FC |
1086 | |
1087 | IDeclaration declaration = null; | |
1088 | List<CommonTree> children = null; | |
3de23137 AM |
1089 | List<CommonTree> pointers = new LinkedList<>(); |
1090 | List<CommonTree> lengths = new LinkedList<>(); | |
866e5b51 FC |
1091 | CommonTree identifier = null; |
1092 | ||
1093 | /* Separate the tokens by type */ | |
1094 | if (typeDeclarator != null) { | |
1095 | children = typeDeclarator.getChildren(); | |
866e5b51 FC |
1096 | for (CommonTree child : children) { |
1097 | ||
1098 | switch (child.getType()) { | |
1099 | case CTFParser.POINTER: | |
1100 | pointers.add(child); | |
1101 | break; | |
1102 | case CTFParser.IDENTIFIER: | |
866e5b51 FC |
1103 | identifier = child; |
1104 | break; | |
1105 | case CTFParser.LENGTH: | |
1106 | lengths.add(child); | |
1107 | break; | |
1108 | default: | |
4ed7d9c1 | 1109 | throw childTypeError(child); |
866e5b51 FC |
1110 | } |
1111 | } | |
1112 | ||
1113 | } | |
1114 | ||
1115 | /* | |
1116 | * Parse the type specifier list, which is the "base" type. For example, | |
1117 | * it would be int in int a[3][len]. | |
1118 | */ | |
94c255ef | 1119 | declaration = parseTypeSpecifierList(typeSpecifierList, pointers, identifier); |
866e5b51 FC |
1120 | |
1121 | /* | |
1122 | * Each length subscript means that we must create a nested array or | |
1123 | * sequence. For example, int a[3][len] means that we have an array of 3 | |
1124 | * (sequences of length 'len' of (int)). | |
1125 | */ | |
62c21477 | 1126 | if (!lengths.isEmpty()) { |
866e5b51 FC |
1127 | /* We begin at the end */ |
1128 | Collections.reverse(lengths); | |
1129 | ||
1130 | for (CommonTree length : lengths) { | |
1131 | /* | |
1132 | * By looking at the first expression, we can determine whether | |
1133 | * it is an array or a sequence. | |
1134 | */ | |
1135 | List<CommonTree> lengthChildren = length.getChildren(); | |
866e5b51 FC |
1136 | |
1137 | CommonTree first = lengthChildren.get(0); | |
1138 | if (isUnaryInteger(first)) { | |
1139 | /* Array */ | |
1140 | int arrayLength = (int) parseUnaryInteger(first); | |
1141 | ||
1142 | if (arrayLength < 1) { | |
1143 | throw new ParseException("Array length is negative"); //$NON-NLS-1$ | |
1144 | } | |
1145 | ||
1146 | /* Create the array declaration. */ | |
1147 | declaration = new ArrayDeclaration(arrayLength, declaration); | |
4311ac8b | 1148 | } else if (isAnyUnaryString(first)) { |
866e5b51 FC |
1149 | /* Sequence */ |
1150 | String lengthName = concatenateUnaryStrings(lengthChildren); | |
1151 | ||
8d90cd62 MK |
1152 | /* check that lengthName was declared */ |
1153 | if (isSignedIntegerField(lengthName)) { | |
1154 | throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$ | |
1155 | } | |
1156 | /* Create the sequence declaration. */ | |
1157 | declaration = new SequenceDeclaration(lengthName, | |
1158 | declaration); | |
1159 | } else if (isTrace(first)) { | |
1160 | /* Sequence */ | |
1161 | String lengthName = parseTraceScope(lengthChildren); | |
1162 | ||
1163 | /* check that lengthName was declared */ | |
1164 | if (isSignedIntegerField(lengthName)) { | |
1165 | throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$ | |
1166 | } | |
1167 | /* Create the sequence declaration. */ | |
1168 | declaration = new SequenceDeclaration(lengthName, | |
1169 | declaration); | |
1170 | ||
1171 | } else if (isStream(first)) { | |
1172 | /* Sequence */ | |
1173 | String lengthName = parseStreamScope(lengthChildren); | |
1174 | ||
1175 | /* check that lengthName was declared */ | |
1176 | if (isSignedIntegerField(lengthName)) { | |
1177 | throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$ | |
1178 | } | |
1179 | /* Create the sequence declaration. */ | |
1180 | declaration = new SequenceDeclaration(lengthName, | |
1181 | declaration); | |
1182 | } else if (isEvent(first)) { | |
1183 | /* Sequence */ | |
1184 | String lengthName = parseEventScope(lengthChildren); | |
1185 | ||
2c053b6e MK |
1186 | /* check that lengthName was declared */ |
1187 | if (isSignedIntegerField(lengthName)) { | |
1188 | throw new ParseException("Sequence declared with length that is not an unsigned integer"); //$NON-NLS-1$ | |
1189 | } | |
866e5b51 FC |
1190 | /* Create the sequence declaration. */ |
1191 | declaration = new SequenceDeclaration(lengthName, | |
1192 | declaration); | |
1193 | } else { | |
4ed7d9c1 | 1194 | throw childTypeError(first); |
866e5b51 FC |
1195 | } |
1196 | } | |
1197 | } | |
1198 | ||
1199 | if (identifier != null) { | |
8d90cd62 MK |
1200 | final String text = identifier.getText(); |
1201 | identifierSB.append(text); | |
1202 | registerType(declaration, text); | |
866e5b51 FC |
1203 | } |
1204 | ||
1205 | return declaration; | |
1206 | } | |
1207 | ||
8d90cd62 MK |
1208 | private void registerType(IDeclaration declaration, String identifier) throws ParseException { |
1209 | final DeclarationScope currentScope = getCurrentScope(); | |
94c255ef | 1210 | if (declaration instanceof EnumDeclaration) { |
8d90cd62 MK |
1211 | currentScope.registerEnum(identifier, (EnumDeclaration) declaration); |
1212 | } else if (declaration instanceof VariantDeclaration) { | |
1213 | currentScope.registerVariant(identifier, (VariantDeclaration) declaration); | |
1214 | } | |
1215 | } | |
1216 | ||
1217 | private static String parseStreamScope(List<CommonTree> lengthChildren) throws ParseException { | |
1218 | List<CommonTree> sublist = lengthChildren.subList(1, lengthChildren.size()); | |
1219 | ||
1220 | CommonTree nextElem = (CommonTree) lengthChildren.get(1).getChild(0); | |
1221 | String lengthName = null; | |
1222 | if (isUnaryString(nextElem)) { | |
1223 | lengthName = parseUnaryString(nextElem); | |
1224 | } | |
1225 | ||
1226 | int type = nextElem.getType(); | |
1227 | if ((CTFParser.tokenNames[CTFParser.EVENT]).equals(lengthName)) { | |
1228 | type = CTFParser.EVENT; | |
1229 | } | |
1230 | switch (type) { | |
1231 | case CTFParser.IDENTIFIER: | |
1232 | lengthName = concatenateUnaryStrings(sublist); | |
1233 | break; | |
1234 | case CTFParser.EVENT: | |
1235 | lengthName = parseEventScope(sublist); | |
1236 | break; | |
1237 | default: | |
1238 | if (lengthName == null) { | |
1239 | throw new ParseException("Unsupported scope stream." + nextElem); //$NON-NLS-1$ | |
1240 | } | |
1241 | } | |
1242 | return MetadataStrings.STREAM + '.' + lengthName; | |
1243 | } | |
1244 | ||
1245 | private static String parseEventScope(List<CommonTree> lengthChildren) throws ParseException { | |
1246 | CommonTree nextElem = (CommonTree) lengthChildren.get(1).getChild(0); | |
1247 | String lengthName; | |
1248 | switch (nextElem.getType()) { | |
1249 | case CTFParser.UNARY_EXPRESSION_STRING: | |
1250 | case CTFParser.IDENTIFIER: | |
1251 | List<CommonTree> sublist = lengthChildren.subList(1, lengthChildren.size()); | |
1252 | lengthName = MetadataStrings.EVENT + '.' + concatenateUnaryStrings(sublist); | |
1253 | break; | |
1254 | default: | |
1255 | throw new ParseException("Unsupported scope event." + nextElem); //$NON-NLS-1$ | |
1256 | } | |
1257 | return lengthName; | |
1258 | } | |
1259 | ||
1260 | private static String parseTraceScope(List<CommonTree> lengthChildren) throws ParseException { | |
1261 | CommonTree nextElem = (CommonTree) lengthChildren.get(1).getChild(0); | |
1262 | String lengthName; | |
1263 | switch (nextElem.getType()) { | |
1264 | case CTFParser.IDENTIFIER: | |
1265 | lengthName = concatenateUnaryStrings(lengthChildren.subList(1, lengthChildren.size())); | |
1266 | break; | |
1267 | case CTFParser.STREAM: | |
1268 | return parseStreamScope(lengthChildren.subList(1, lengthChildren.size())); | |
1269 | default: | |
1270 | throw new ParseException("Unsupported scope trace." + nextElem); //$NON-NLS-1$ | |
1271 | } | |
1272 | return lengthName; | |
1273 | } | |
1274 | ||
1275 | private static boolean isEvent(CommonTree first) { | |
1276 | return first.getType() == CTFParser.EVENT; | |
1277 | } | |
1278 | ||
1279 | private static boolean isStream(CommonTree first) { | |
1280 | return first.getType() == CTFParser.STREAM; | |
1281 | } | |
1282 | ||
1283 | private static boolean isTrace(CommonTree first) { | |
1284 | return first.getType() == CTFParser.TRACE; | |
1285 | } | |
1286 | ||
2c053b6e MK |
1287 | private boolean isSignedIntegerField(String lengthName) throws ParseException { |
1288 | IDeclaration decl = getCurrentScope().lookupIdentifierRecursive(lengthName); | |
1289 | if (decl instanceof IntegerDeclaration) { | |
1290 | return ((IntegerDeclaration) decl).isSigned(); | |
1291 | } | |
1292 | throw new ParseException("Is not an integer: " + lengthName); //$NON-NLS-1$ | |
1293 | ||
1294 | } | |
1295 | ||
94c255ef MK |
1296 | private IDeclaration parseTypeSpecifierList(CommonTree typeSpecifierList) throws ParseException { |
1297 | return parseTypeSpecifierList(typeSpecifierList, null, null); | |
1298 | } | |
1299 | ||
866e5b51 FC |
1300 | /** |
1301 | * Parses a type specifier list and returns the corresponding declaration. | |
1302 | * | |
1303 | * @param typeSpecifierList | |
1304 | * A TYPE_SPECIFIER_LIST node. | |
1305 | * @param pointerList | |
1306 | * A list of POINTER nodes that apply to the specified type. | |
1307 | * @return The corresponding declaration. | |
1308 | * @throws ParseException | |
1309 | * If the type has not been defined or if there is an error | |
1310 | * creating the declaration. | |
1311 | */ | |
1312 | private IDeclaration parseTypeSpecifierList(CommonTree typeSpecifierList, | |
94c255ef | 1313 | List<CommonTree> pointerList, CommonTree identifier) throws ParseException { |
866e5b51 FC |
1314 | IDeclaration declaration = null; |
1315 | ||
1316 | /* | |
1317 | * By looking at the first element of the type specifier list, we can | |
1318 | * determine which type it belongs to. | |
1319 | */ | |
1320 | CommonTree firstChild = (CommonTree) typeSpecifierList.getChild(0); | |
866e5b51 FC |
1321 | |
1322 | switch (firstChild.getType()) { | |
1323 | case CTFParser.FLOATING_POINT: | |
53047a66 | 1324 | declaration = parseFloat(firstChild); |
866e5b51 FC |
1325 | break; |
1326 | case CTFParser.INTEGER: | |
1327 | declaration = parseInteger(firstChild); | |
1328 | break; | |
1329 | case CTFParser.STRING: | |
1330 | declaration = parseString(firstChild); | |
1331 | break; | |
1332 | case CTFParser.STRUCT: | |
94c255ef | 1333 | declaration = parseStruct(firstChild, identifier); |
6c7592e1 MK |
1334 | StructDeclaration structDeclaration = (StructDeclaration) declaration; |
1335 | IDeclaration idEnumDecl = structDeclaration.getFields().get("id"); //$NON-NLS-1$ | |
66aa25f0 MK |
1336 | if (idEnumDecl instanceof EnumDeclaration) { |
1337 | EnumDeclaration enumDeclaration = (EnumDeclaration) idEnumDecl; | |
1338 | ByteOrder bo = enumDeclaration.getContainerType().getByteOrder(); | |
1339 | if (EventHeaderCompactDeclaration.getEventHeader(bo).isCompactEventHeader(structDeclaration)) { | |
1340 | declaration = EventHeaderCompactDeclaration.getEventHeader(bo); | |
1341 | } else if (EventHeaderLargeDeclaration.getEventHeader(bo).isLargeEventHeader(structDeclaration)) { | |
1342 | declaration = EventHeaderLargeDeclaration.getEventHeader(bo); | |
1343 | } | |
6c7592e1 | 1344 | } |
866e5b51 FC |
1345 | break; |
1346 | case CTFParser.VARIANT: | |
1347 | declaration = parseVariant(firstChild); | |
1348 | break; | |
1349 | case CTFParser.ENUM: | |
1350 | declaration = parseEnum(firstChild); | |
1351 | break; | |
1352 | case CTFParser.IDENTIFIER: | |
1353 | case CTFParser.FLOATTOK: | |
1354 | case CTFParser.INTTOK: | |
1355 | case CTFParser.LONGTOK: | |
1356 | case CTFParser.SHORTTOK: | |
1357 | case CTFParser.SIGNEDTOK: | |
1358 | case CTFParser.UNSIGNEDTOK: | |
1359 | case CTFParser.CHARTOK: | |
1360 | case CTFParser.DOUBLETOK: | |
1361 | case CTFParser.VOIDTOK: | |
1362 | case CTFParser.BOOLTOK: | |
1363 | case CTFParser.COMPLEXTOK: | |
1364 | case CTFParser.IMAGINARYTOK: | |
1365 | declaration = parseTypeDeclaration(typeSpecifierList, pointerList); | |
1366 | break; | |
1367 | default: | |
4ed7d9c1 | 1368 | throw childTypeError(firstChild); |
866e5b51 FC |
1369 | } |
1370 | ||
866e5b51 FC |
1371 | return declaration; |
1372 | } | |
1373 | ||
32ede2ec MK |
1374 | private IDeclaration parseFloat(CommonTree floatingPoint) |
1375 | throws ParseException { | |
53047a66 MK |
1376 | |
1377 | List<CommonTree> children = floatingPoint.getChildren(); | |
1378 | ||
1379 | /* | |
1380 | * If the integer has no attributes, then it is missing the size | |
1381 | * attribute which is required | |
1382 | */ | |
1383 | if (children == null) { | |
1384 | throw new ParseException("float: missing size attribute"); //$NON-NLS-1$ | |
1385 | } | |
1386 | ||
1387 | /* The return value */ | |
1388 | FloatDeclaration floatDeclaration = null; | |
9226cfc5 | 1389 | ByteOrder byteOrder = fTrace.getByteOrder(); |
53047a66 | 1390 | long alignment = 0; |
466f6d95 MK |
1391 | |
1392 | int exponent = DEFAULT_FLOAT_EXPONENT; | |
1393 | int mantissa = DEFAULT_FLOAT_MANTISSA; | |
53047a66 | 1394 | |
53047a66 MK |
1395 | /* Iterate on all integer children */ |
1396 | for (CommonTree child : children) { | |
1397 | switch (child.getType()) { | |
1398 | case CTFParser.CTF_EXPRESSION_VAL: | |
1399 | /* | |
1400 | * An assignment expression must have 2 children, left and right | |
1401 | */ | |
53047a66 MK |
1402 | |
1403 | CommonTree leftNode = (CommonTree) child.getChild(0); | |
53047a66 | 1404 | CommonTree rightNode = (CommonTree) child.getChild(1); |
53047a66 MK |
1405 | |
1406 | List<CommonTree> leftStrings = leftNode.getChildren(); | |
53047a66 | 1407 | |
4311ac8b | 1408 | if (!isAnyUnaryString(leftStrings.get(0))) { |
2c053b6e | 1409 | throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$ |
53047a66 MK |
1410 | } |
1411 | String left = concatenateUnaryStrings(leftStrings); | |
1412 | ||
fafc36a7 | 1413 | if (left.equals(MetadataStrings.EXP_DIG)) { |
53047a66 | 1414 | exponent = (int) parseUnaryInteger((CommonTree) rightNode.getChild(0)); |
fafc36a7 | 1415 | } else if (left.equals(MetadataStrings.BYTE_ORDER)) { |
53047a66 | 1416 | byteOrder = getByteOrder(rightNode); |
fafc36a7 | 1417 | } else if (left.equals(MetadataStrings.MANT_DIG)) { |
53047a66 | 1418 | mantissa = (int) parseUnaryInteger((CommonTree) rightNode.getChild(0)); |
fafc36a7 | 1419 | } else if (left.equals(MetadataStrings.ALIGN)) { |
53047a66 MK |
1420 | alignment = getAlignment(rightNode); |
1421 | } else { | |
1422 | throw new ParseException("Float: unknown attribute " + left); //$NON-NLS-1$ | |
1423 | } | |
1424 | ||
1425 | break; | |
1426 | default: | |
4ed7d9c1 | 1427 | throw childTypeError(child); |
53047a66 MK |
1428 | } |
1429 | } | |
1430 | int size = mantissa + exponent; | |
1431 | if (size == 0) { | |
1432 | throw new ParseException("Float missing size attribute"); //$NON-NLS-1$ | |
1433 | } | |
1434 | ||
1435 | if (alignment == 0) { | |
466f6d95 | 1436 | alignment = ((size % DEFAULT_ALIGNMENT) == 0) ? 1 : DEFAULT_ALIGNMENT; |
53047a66 MK |
1437 | } |
1438 | ||
07002e0a | 1439 | floatDeclaration = new FloatDeclaration(exponent, mantissa, byteOrder, alignment); |
53047a66 | 1440 | |
53047a66 MK |
1441 | return floatDeclaration; |
1442 | ||
1443 | } | |
1444 | ||
866e5b51 FC |
1445 | /** |
1446 | * Parses a type specifier list as a user-declared type. | |
1447 | * | |
1448 | * @param typeSpecifierList | |
1449 | * A TYPE_SPECIFIER_LIST node containing a user-declared type. | |
1450 | * @param pointerList | |
1451 | * A list of POINTER nodes that apply to the type specified in | |
1452 | * typeSpecifierList. | |
1453 | * @return The corresponding declaration. | |
1454 | * @throws ParseException | |
1455 | * If the type does not exist (has not been found). | |
1456 | */ | |
1457 | private IDeclaration parseTypeDeclaration(CommonTree typeSpecifierList, | |
1458 | List<CommonTree> pointerList) throws ParseException { | |
1459 | /* Create the string representation of the type declaration */ | |
1460 | String typeStringRepresentation = createTypeDeclarationString( | |
1461 | typeSpecifierList, pointerList); | |
1462 | ||
3ba65808 MK |
1463 | /* |
1464 | * Use the string representation to search the type in the current scope | |
1465 | */ | |
2c053b6e | 1466 | IDeclaration decl = getCurrentScope().lookupTypeRecursive( |
866e5b51 FC |
1467 | typeStringRepresentation); |
1468 | ||
1469 | if (decl == null) { | |
1470 | throw new ParseException("Type " + typeStringRepresentation //$NON-NLS-1$ | |
1471 | + " has not been defined."); //$NON-NLS-1$ | |
1472 | } | |
1473 | ||
1474 | return decl; | |
1475 | } | |
1476 | ||
1477 | /** | |
1478 | * Parses an integer declaration node. | |
1479 | * | |
1480 | * @param integer | |
1481 | * An INTEGER node. | |
1482 | * @return The corresponding integer declaration. | |
1483 | * @throws ParseException | |
1484 | */ | |
1485 | private IntegerDeclaration parseInteger(CommonTree integer) | |
1486 | throws ParseException { | |
866e5b51 FC |
1487 | |
1488 | List<CommonTree> children = integer.getChildren(); | |
1489 | ||
1490 | /* | |
1491 | * If the integer has no attributes, then it is missing the size | |
1492 | * attribute which is required | |
1493 | */ | |
1494 | if (children == null) { | |
1495 | throw new ParseException("integer: missing size attribute"); //$NON-NLS-1$ | |
1496 | } | |
1497 | ||
1498 | /* The return value */ | |
1499 | IntegerDeclaration integerDeclaration = null; | |
1500 | boolean signed = false; | |
9226cfc5 | 1501 | ByteOrder byteOrder = fTrace.getByteOrder(); |
866e5b51 FC |
1502 | long size = 0; |
1503 | long alignment = 0; | |
466f6d95 | 1504 | int base = DEFAULT_INT_BASE; |
a4fa4e36 | 1505 | @NonNull |
62c21477 | 1506 | String clock = EMPTY_STRING; |
866e5b51 FC |
1507 | |
1508 | Encoding encoding = Encoding.NONE; | |
1509 | ||
1510 | /* Iterate on all integer children */ | |
1511 | for (CommonTree child : children) { | |
1512 | switch (child.getType()) { | |
1513 | case CTFParser.CTF_EXPRESSION_VAL: | |
1514 | /* | |
1515 | * An assignment expression must have 2 children, left and right | |
1516 | */ | |
866e5b51 FC |
1517 | |
1518 | CommonTree leftNode = (CommonTree) child.getChild(0); | |
866e5b51 | 1519 | CommonTree rightNode = (CommonTree) child.getChild(1); |
866e5b51 FC |
1520 | |
1521 | List<CommonTree> leftStrings = leftNode.getChildren(); | |
866e5b51 | 1522 | |
4311ac8b | 1523 | if (!isAnyUnaryString(leftStrings.get(0))) { |
2c053b6e | 1524 | throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$ |
866e5b51 FC |
1525 | } |
1526 | String left = concatenateUnaryStrings(leftStrings); | |
1527 | ||
62c21477 | 1528 | if (left.equals(SIGNED)) { |
866e5b51 | 1529 | signed = getSigned(rightNode); |
fafc36a7 | 1530 | } else if (left.equals(MetadataStrings.BYTE_ORDER)) { |
866e5b51 | 1531 | byteOrder = getByteOrder(rightNode); |
62c21477 | 1532 | } else if (left.equals(SIZE)) { |
866e5b51 | 1533 | size = getSize(rightNode); |
fafc36a7 | 1534 | } else if (left.equals(MetadataStrings.ALIGN)) { |
866e5b51 | 1535 | alignment = getAlignment(rightNode); |
62c21477 | 1536 | } else if (left.equals(BASE)) { |
866e5b51 | 1537 | base = getBase(rightNode); |
62c21477 | 1538 | } else if (left.equals(ENCODING)) { |
866e5b51 | 1539 | encoding = getEncoding(rightNode); |
62c21477 | 1540 | } else if (left.equals(MAP)) { |
866e5b51 FC |
1541 | clock = getClock(rightNode); |
1542 | } else { | |
4311ac8b | 1543 | Activator.log(IStatus.WARNING, Messages.IOStructGen_UnknownIntegerAttributeWarning + " " + left); //$NON-NLS-1$ |
866e5b51 FC |
1544 | } |
1545 | ||
1546 | break; | |
1547 | default: | |
4ed7d9c1 | 1548 | throw childTypeError(child); |
866e5b51 FC |
1549 | } |
1550 | } | |
1551 | ||
6fbc2ff7 AM |
1552 | if (size <= 0) { |
1553 | throw new ParseException("Invalid size attribute in Integer: " + size); //$NON-NLS-1$ | |
866e5b51 FC |
1554 | } |
1555 | ||
1556 | if (alignment == 0) { | |
466f6d95 | 1557 | alignment = ((size % DEFAULT_ALIGNMENT) == 0) ? 1 : DEFAULT_ALIGNMENT; |
866e5b51 FC |
1558 | } |
1559 | ||
a4fa4e36 | 1560 | integerDeclaration = IntegerDeclaration.createDeclaration((int) size, signed, base, |
fd74e6c1 | 1561 | byteOrder, encoding, clock, alignment); |
866e5b51 | 1562 | |
866e5b51 FC |
1563 | return integerDeclaration; |
1564 | } | |
1565 | ||
a4fa4e36 | 1566 | @NonNull |
284fdee8 | 1567 | private static String getClock(CommonTree rightNode) { |
a4fa4e36 | 1568 | String clock = rightNode.getChild(1).getChild(0).getChild(0).getText(); |
62c21477 | 1569 | return clock == null ? EMPTY_STRING : clock; |
866e5b51 FC |
1570 | } |
1571 | ||
1572 | private static StringDeclaration parseString(CommonTree string) | |
1573 | throws ParseException { | |
866e5b51 FC |
1574 | |
1575 | List<CommonTree> children = string.getChildren(); | |
1576 | StringDeclaration stringDeclaration = null; | |
1577 | ||
1578 | if (children == null) { | |
d890ec37 | 1579 | stringDeclaration = StringDeclaration.getStringDeclaration(Encoding.UTF8); |
866e5b51 FC |
1580 | } else { |
1581 | Encoding encoding = Encoding.UTF8; | |
1582 | for (CommonTree child : children) { | |
1583 | switch (child.getType()) { | |
1584 | case CTFParser.CTF_EXPRESSION_VAL: | |
1585 | /* | |
1586 | * An assignment expression must have 2 children, left and | |
1587 | * right | |
1588 | */ | |
866e5b51 FC |
1589 | |
1590 | CommonTree leftNode = (CommonTree) child.getChild(0); | |
866e5b51 | 1591 | CommonTree rightNode = (CommonTree) child.getChild(1); |
866e5b51 FC |
1592 | |
1593 | List<CommonTree> leftStrings = leftNode.getChildren(); | |
866e5b51 | 1594 | |
4311ac8b | 1595 | if (!isAnyUnaryString(leftStrings.get(0))) { |
2c053b6e | 1596 | throw new ParseException("Left side of ctf expression must be a string"); //$NON-NLS-1$ |
866e5b51 FC |
1597 | } |
1598 | String left = concatenateUnaryStrings(leftStrings); | |
1599 | ||
62c21477 | 1600 | if (left.equals(ENCODING)) { |
866e5b51 FC |
1601 | encoding = getEncoding(rightNode); |
1602 | } else { | |
1603 | throw new ParseException("String: unknown attribute " //$NON-NLS-1$ | |
1604 | + left); | |
1605 | } | |
1606 | ||
1607 | break; | |
1608 | default: | |
4ed7d9c1 | 1609 | throw childTypeError(child); |
866e5b51 FC |
1610 | } |
1611 | } | |
1612 | ||
d890ec37 | 1613 | stringDeclaration = StringDeclaration.getStringDeclaration(encoding); |
866e5b51 FC |
1614 | } |
1615 | ||
1616 | return stringDeclaration; | |
1617 | } | |
1618 | ||
1619 | /** | |
1620 | * Parses a struct declaration and returns the corresponding declaration. | |
1621 | * | |
1622 | * @param struct | |
1623 | * An STRUCT node. | |
1624 | * @return The corresponding struct declaration. | |
1625 | * @throws ParseException | |
1626 | */ | |
94c255ef | 1627 | private StructDeclaration parseStruct(CommonTree struct, CommonTree identifier) |
866e5b51 | 1628 | throws ParseException { |
866e5b51 FC |
1629 | |
1630 | List<CommonTree> children = struct.getChildren(); | |
866e5b51 FC |
1631 | |
1632 | /* The return value */ | |
1633 | StructDeclaration structDeclaration = null; | |
1634 | ||
1635 | /* Name */ | |
1636 | String structName = null; | |
1637 | boolean hasName = false; | |
1638 | ||
1639 | /* Body */ | |
1640 | CommonTree structBody = null; | |
1641 | boolean hasBody = false; | |
1642 | ||
1643 | /* Align */ | |
1644 | long structAlign = 0; | |
1645 | ||
1646 | /* Loop on all children and identify what we have to work with. */ | |
1647 | for (CommonTree child : children) { | |
1648 | switch (child.getType()) { | |
1649 | case CTFParser.STRUCT_NAME: { | |
1650 | hasName = true; | |
72dbc4ac | 1651 | CommonTree structNameIdentifier = (CommonTree) child.getChild(0); |
866e5b51 | 1652 | structName = structNameIdentifier.getText(); |
866e5b51 FC |
1653 | break; |
1654 | } | |
1655 | case CTFParser.STRUCT_BODY: { | |
1656 | hasBody = true; | |
1657 | ||
1658 | structBody = child; | |
866e5b51 FC |
1659 | break; |
1660 | } | |
1661 | case CTFParser.ALIGN: { | |
72dbc4ac | 1662 | CommonTree structAlignExpression = (CommonTree) child.getChild(0); |
866e5b51 FC |
1663 | |
1664 | structAlign = getAlignment(structAlignExpression); | |
866e5b51 FC |
1665 | break; |
1666 | } | |
1667 | default: | |
4ed7d9c1 | 1668 | throw childTypeError(child); |
866e5b51 FC |
1669 | } |
1670 | } | |
1671 | ||
94c255ef MK |
1672 | if (!hasName && identifier != null) { |
1673 | structName = identifier.getText(); | |
1674 | hasName = true; | |
1675 | } | |
1676 | ||
866e5b51 FC |
1677 | /* |
1678 | * If a struct has just a body and no name (just like the song, | |
1679 | * "A Struct With No Name" by America (sorry for that...)), it's a | |
1680 | * definition of a new type, so we create the type declaration and | |
1681 | * return it. We can't add it to the declaration scope since there is no | |
1682 | * name, but that's what we want because it won't be possible to use it | |
1683 | * again to declare another field. | |
1684 | * | |
1685 | * If it has just a name, we look it up in the declaration scope and | |
1686 | * return the associated declaration. If it is not found in the | |
1687 | * declaration scope, it means that a struct with that name has not been | |
1688 | * declared, which is an error. | |
1689 | * | |
1690 | * If it has both, then we create the type declaration and register it | |
1691 | * to the current scope. | |
1692 | * | |
1693 | * If it has none, then what are we doing here ? | |
1694 | */ | |
1695 | if (hasBody) { | |
1696 | /* | |
1697 | * If struct has a name, check if already defined in the current | |
1698 | * scope. | |
1699 | */ | |
1700 | if (hasName && (getCurrentScope().lookupStruct(structName) != null)) { | |
1701 | throw new ParseException("struct " + structName //$NON-NLS-1$ | |
1702 | + " already defined."); //$NON-NLS-1$ | |
1703 | } | |
866e5b51 FC |
1704 | /* Create the declaration */ |
1705 | structDeclaration = new StructDeclaration(structAlign); | |
1706 | ||
1707 | /* Parse the body */ | |
3ba65808 | 1708 | parseStructBody(structBody, structDeclaration, structName); |
866e5b51 FC |
1709 | |
1710 | /* If struct has name, add it to the current scope. */ | |
1711 | if (hasName) { | |
1712 | getCurrentScope().registerStruct(structName, structDeclaration); | |
1713 | } | |
3ba65808 | 1714 | } else /* !hasBody */ { |
866e5b51 FC |
1715 | if (hasName) { |
1716 | /* Name and !body */ | |
1717 | ||
1718 | /* Lookup the name in the current scope. */ | |
2c053b6e | 1719 | structDeclaration = getCurrentScope().lookupStructRecursive(structName); |
866e5b51 FC |
1720 | |
1721 | /* | |
1722 | * If not found, it means that a struct with such name has not | |
1723 | * been defined | |
1724 | */ | |
1725 | if (structDeclaration == null) { | |
1726 | throw new ParseException("struct " + structName //$NON-NLS-1$ | |
1727 | + " is not defined"); //$NON-NLS-1$ | |
1728 | } | |
1729 | } else { | |
1730 | /* !Name and !body */ | |
1731 | ||
1732 | /* We can't do anything with that. */ | |
1733 | throw new ParseException("struct with no name and no body"); //$NON-NLS-1$ | |
1734 | } | |
1735 | } | |
8fa270f6 | 1736 | return StructDeclarationFlattener.tryFlattenStruct(structDeclaration); |
866e5b51 FC |
1737 | } |
1738 | ||
1739 | /** | |
1740 | * Parses a struct body, adding the fields to specified structure | |
1741 | * declaration. | |
1742 | * | |
1743 | * @param structBody | |
1744 | * A STRUCT_BODY node. | |
1745 | * @param structDeclaration | |
1746 | * The struct declaration. | |
1747 | * @throws ParseException | |
1748 | */ | |
1749 | private void parseStructBody(CommonTree structBody, | |
3ba65808 | 1750 | StructDeclaration structDeclaration, @Nullable String structName) throws ParseException { |
866e5b51 | 1751 | List<CommonTree> structDeclarations = structBody.getChildren(); |
3ba65808 MK |
1752 | if (structDeclarations == null) { |
1753 | structDeclarations = Collections.emptyList(); | |
1754 | } | |
866e5b51 FC |
1755 | |
1756 | /* | |
1757 | * If structDeclaration is null, structBody has no children and the | |
1758 | * struct body is empty. | |
1759 | */ | |
3ba65808 | 1760 | pushNamedScope(structName, MetadataStrings.STRUCT); |
866e5b51 | 1761 | |
3ba65808 MK |
1762 | for (CommonTree declarationNode : structDeclarations) { |
1763 | switch (declarationNode.getType()) { | |
1764 | case CTFParser.TYPEALIAS: | |
1765 | parseTypealias(declarationNode); | |
1766 | break; | |
1767 | case CTFParser.TYPEDEF: | |
1768 | parseTypedef(declarationNode); | |
94c255ef | 1769 | parseStructDeclaration(declarationNode, structDeclaration); |
3ba65808 MK |
1770 | break; |
1771 | case CTFParser.SV_DECLARATION: | |
1772 | parseStructDeclaration(declarationNode, structDeclaration); | |
1773 | break; | |
1774 | default: | |
1775 | throw childTypeError(declarationNode); | |
866e5b51 | 1776 | } |
866e5b51 | 1777 | } |
3ba65808 | 1778 | popScope(); |
866e5b51 FC |
1779 | } |
1780 | ||
1781 | /** | |
1782 | * Parses a declaration found in a struct. | |
1783 | * | |
1784 | * @param declaration | |
1785 | * A SV_DECLARATION node. | |
1786 | * @param struct | |
1787 | * A struct declaration. (I know, little name clash here...) | |
1788 | * @throws ParseException | |
1789 | */ | |
1790 | private void parseStructDeclaration(CommonTree declaration, | |
1791 | StructDeclaration struct) throws ParseException { | |
866e5b51 | 1792 | |
866e5b51 | 1793 | /* Get the type specifier list node */ |
72dbc4ac | 1794 | CommonTree typeSpecifierListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST); |
866e5b51 FC |
1795 | |
1796 | /* Get the type declarator list node */ | |
72dbc4ac | 1797 | CommonTree typeDeclaratorListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST); |
866e5b51 FC |
1798 | |
1799 | /* Get the type declarator list */ | |
72dbc4ac | 1800 | List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren(); |
866e5b51 FC |
1801 | |
1802 | /* | |
1803 | * For each type declarator, parse the declaration and add a field to | |
1804 | * the struct | |
1805 | */ | |
1806 | for (CommonTree typeDeclaratorNode : typeDeclaratorList) { | |
866e5b51 FC |
1807 | |
1808 | StringBuilder identifierSB = new StringBuilder(); | |
1809 | ||
1810 | IDeclaration decl = parseTypeDeclarator(typeDeclaratorNode, | |
1811 | typeSpecifierListNode, identifierSB); | |
1812 | String fieldName = identifierSB.toString(); | |
2c053b6e | 1813 | getCurrentScope().registerIdentifier(fieldName, decl); |
866e5b51 FC |
1814 | |
1815 | if (struct.hasField(fieldName)) { | |
1816 | throw new ParseException("struct: duplicate field " //$NON-NLS-1$ | |
1817 | + fieldName); | |
1818 | } | |
1819 | ||
1820 | struct.addField(fieldName, decl); | |
1821 | ||
1822 | } | |
1823 | } | |
1824 | ||
1825 | /** | |
1826 | * Parses an enum declaration and returns the corresponding declaration. | |
1827 | * | |
0594c61c | 1828 | * @param theEnum |
866e5b51 FC |
1829 | * An ENUM node. |
1830 | * @return The corresponding enum declaration. | |
1831 | * @throws ParseException | |
1832 | */ | |
0594c61c | 1833 | private EnumDeclaration parseEnum(CommonTree theEnum) throws ParseException { |
866e5b51 | 1834 | |
0594c61c | 1835 | List<CommonTree> children = theEnum.getChildren(); |
866e5b51 FC |
1836 | |
1837 | /* The return value */ | |
1838 | EnumDeclaration enumDeclaration = null; | |
1839 | ||
1840 | /* Name */ | |
1841 | String enumName = null; | |
1842 | ||
1843 | /* Body */ | |
1844 | CommonTree enumBody = null; | |
1845 | ||
1846 | /* Container type */ | |
1847 | IntegerDeclaration containerTypeDeclaration = null; | |
1848 | ||
1849 | /* Loop on all children and identify what we have to work with. */ | |
1850 | for (CommonTree child : children) { | |
1851 | switch (child.getType()) { | |
1852 | case CTFParser.ENUM_NAME: { | |
866e5b51 | 1853 | CommonTree enumNameIdentifier = (CommonTree) child.getChild(0); |
866e5b51 | 1854 | enumName = enumNameIdentifier.getText(); |
866e5b51 FC |
1855 | break; |
1856 | } | |
1857 | case CTFParser.ENUM_BODY: { | |
866e5b51 | 1858 | enumBody = child; |
866e5b51 FC |
1859 | break; |
1860 | } | |
1861 | case CTFParser.ENUM_CONTAINER_TYPE: { | |
866e5b51 | 1862 | containerTypeDeclaration = parseEnumContainerType(child); |
866e5b51 FC |
1863 | break; |
1864 | } | |
1865 | default: | |
4ed7d9c1 | 1866 | throw childTypeError(child); |
866e5b51 FC |
1867 | } |
1868 | } | |
1869 | ||
1870 | /* | |
1871 | * If the container type has not been defined explicitly, we assume it | |
1872 | * is "int". | |
1873 | */ | |
1874 | if (containerTypeDeclaration == null) { | |
32ede2ec MK |
1875 | IDeclaration enumDecl; |
1876 | /* | |
1877 | * it could be because the enum was already declared. | |
1878 | */ | |
1879 | if (enumName != null) { | |
3ba65808 | 1880 | getCurrentScope().setName(enumName); |
2c053b6e | 1881 | enumDecl = getCurrentScope().lookupEnumRecursive(enumName); |
32ede2ec MK |
1882 | if (enumDecl != null) { |
1883 | return (EnumDeclaration) enumDecl; | |
1884 | } | |
1885 | } | |
1886 | ||
2c053b6e | 1887 | IDeclaration decl = getCurrentScope().lookupTypeRecursive("int"); //$NON-NLS-1$ |
866e5b51 FC |
1888 | |
1889 | if (decl == null) { | |
2c053b6e | 1890 | throw new ParseException("enum container type implicit and type int not defined"); //$NON-NLS-1$ |
866e5b51 | 1891 | } else if (!(decl instanceof IntegerDeclaration)) { |
2c053b6e | 1892 | throw new ParseException("enum container type implicit and type int not an integer"); //$NON-NLS-1$ |
866e5b51 FC |
1893 | } |
1894 | ||
1895 | containerTypeDeclaration = (IntegerDeclaration) decl; | |
1896 | } | |
1897 | ||
1898 | /* | |
1899 | * If it has a body, it's a new declaration, otherwise it's a reference | |
1900 | * to an existing declaration. Same logic as struct. | |
1901 | */ | |
1902 | if (enumBody != null) { | |
1903 | /* | |
1904 | * If enum has a name, check if already defined in the current | |
1905 | * scope. | |
1906 | */ | |
1907 | if ((enumName != null) | |
1908 | && (getCurrentScope().lookupEnum(enumName) != null)) { | |
1909 | throw new ParseException("enum " + enumName //$NON-NLS-1$ | |
1910 | + " already defined"); //$NON-NLS-1$ | |
1911 | } | |
1912 | ||
1913 | /* Create the declaration */ | |
1914 | enumDeclaration = new EnumDeclaration(containerTypeDeclaration); | |
1915 | ||
1916 | /* Parse the body */ | |
3ba65808 | 1917 | parseEnumBody(enumBody, enumDeclaration, enumName); |
866e5b51 FC |
1918 | |
1919 | /* If the enum has name, add it to the current scope. */ | |
1920 | if (enumName != null) { | |
1921 | getCurrentScope().registerEnum(enumName, enumDeclaration); | |
1922 | } | |
1923 | } else { | |
1924 | if (enumName != null) { | |
1925 | /* Name and !body */ | |
1926 | ||
1927 | /* Lookup the name in the current scope. */ | |
2c053b6e | 1928 | enumDeclaration = getCurrentScope().lookupEnumRecursive(enumName); |
866e5b51 FC |
1929 | |
1930 | /* | |
1931 | * If not found, it means that an enum with such name has not | |
1932 | * been defined | |
1933 | */ | |
1934 | if (enumDeclaration == null) { | |
1935 | throw new ParseException("enum " + enumName //$NON-NLS-1$ | |
1936 | + " is not defined"); //$NON-NLS-1$ | |
1937 | } | |
1938 | } else { | |
1939 | /* !Name and !body */ | |
1940 | throw new ParseException("enum with no name and no body"); //$NON-NLS-1$ | |
1941 | } | |
1942 | } | |
1943 | ||
1944 | return enumDeclaration; | |
1945 | ||
1946 | } | |
1947 | ||
1948 | /** | |
1949 | * Parses an enum body, adding the enumerators to the specified enum | |
1950 | * declaration. | |
1951 | * | |
1952 | * @param enumBody | |
1953 | * An ENUM_BODY node. | |
1954 | * @param enumDeclaration | |
1955 | * The enum declaration. | |
1956 | * @throws ParseException | |
1957 | */ | |
1958 | private void parseEnumBody(CommonTree enumBody, | |
3ba65808 | 1959 | EnumDeclaration enumDeclaration, @Nullable String enumName) throws ParseException { |
866e5b51 FC |
1960 | |
1961 | List<CommonTree> enumerators = enumBody.getChildren(); | |
1962 | /* enum body can't be empty (unlike struct). */ | |
866e5b51 | 1963 | |
3ba65808 | 1964 | pushNamedScope(enumName, MetadataStrings.ENUM); |
866e5b51 FC |
1965 | |
1966 | /* | |
1967 | * Start at -1, so that if the first enumrator has no explicit value, it | |
1968 | * will choose 0 | |
1969 | */ | |
1970 | long lastHigh = -1; | |
1971 | ||
1972 | for (CommonTree enumerator : enumerators) { | |
1973 | lastHigh = parseEnumEnumerator(enumerator, enumDeclaration, | |
1974 | lastHigh); | |
1975 | } | |
1976 | ||
1977 | popScope(); | |
1978 | ||
1979 | } | |
1980 | ||
1981 | /** | |
1982 | * Parses an enumerator node and adds an enumerator declaration to an | |
1983 | * enumeration declaration. | |
1984 | * | |
1985 | * The high value of the range of the last enumerator is needed in case the | |
1986 | * current enumerator does not specify its value. | |
1987 | * | |
1988 | * @param enumerator | |
1989 | * An ENUM_ENUMERATOR node. | |
1990 | * @param enumDeclaration | |
1991 | * en enumeration declaration to which will be added the | |
1992 | * enumerator. | |
1993 | * @param lastHigh | |
1994 | * The high value of the range of the last enumerator | |
1995 | * @return The high value of the value range of the current enumerator. | |
1996 | * @throws ParseException | |
1997 | */ | |
1998 | private static long parseEnumEnumerator(CommonTree enumerator, | |
1999 | EnumDeclaration enumDeclaration, long lastHigh) | |
3ba65808 | 2000 | throws ParseException { |
866e5b51 FC |
2001 | |
2002 | List<CommonTree> children = enumerator.getChildren(); | |
866e5b51 FC |
2003 | |
2004 | long low = 0, high = 0; | |
2005 | boolean valueSpecified = false; | |
2006 | String label = null; | |
2007 | ||
2008 | for (CommonTree child : children) { | |
4311ac8b | 2009 | if (isAnyUnaryString(child)) { |
866e5b51 FC |
2010 | label = parseUnaryString(child); |
2011 | } else if (child.getType() == CTFParser.ENUM_VALUE) { | |
866e5b51 FC |
2012 | |
2013 | valueSpecified = true; | |
2014 | ||
2015 | low = parseUnaryInteger((CommonTree) child.getChild(0)); | |
2016 | high = low; | |
2017 | } else if (child.getType() == CTFParser.ENUM_VALUE_RANGE) { | |
866e5b51 FC |
2018 | |
2019 | valueSpecified = true; | |
2020 | ||
2021 | low = parseUnaryInteger((CommonTree) child.getChild(0)); | |
2022 | high = parseUnaryInteger((CommonTree) child.getChild(1)); | |
2023 | } else { | |
4ed7d9c1 | 2024 | throw childTypeError(child); |
866e5b51 FC |
2025 | } |
2026 | } | |
2027 | ||
866e5b51 FC |
2028 | if (!valueSpecified) { |
2029 | low = lastHigh + 1; | |
2030 | high = low; | |
2031 | } | |
2032 | ||
2033 | if (low > high) { | |
2034 | throw new ParseException("enum low value greater than high value"); //$NON-NLS-1$ | |
2035 | } | |
2036 | ||
2037 | if (!enumDeclaration.add(low, high, label)) { | |
2038 | throw new ParseException("enum declarator values overlap."); //$NON-NLS-1$ | |
2039 | } | |
2040 | ||
4311ac8b MAL |
2041 | if (valueSpecified && (BigInteger.valueOf(low).compareTo(enumDeclaration.getContainerType().getMinValue()) == -1 || |
2042 | BigInteger.valueOf(high).compareTo(enumDeclaration.getContainerType().getMaxValue()) == 1)) { | |
2043 | throw new ParseException("enum value is not in range"); //$NON-NLS-1$ | |
2044 | } | |
2045 | ||
866e5b51 FC |
2046 | return high; |
2047 | } | |
2048 | ||
2049 | /** | |
2050 | * Parses an enum container type node and returns the corresponding integer | |
2051 | * type. | |
2052 | * | |
2053 | * @param enumContainerType | |
2054 | * An ENUM_CONTAINER_TYPE node. | |
2055 | * @return An integer declaration corresponding to the container type. | |
2056 | * @throws ParseException | |
2057 | * If the type does not parse correctly or if it is not an | |
2058 | * integer type. | |
2059 | */ | |
2060 | private IntegerDeclaration parseEnumContainerType( | |
2061 | CommonTree enumContainerType) throws ParseException { | |
866e5b51 FC |
2062 | |
2063 | /* Get the child, which should be a type specifier list */ | |
72dbc4ac | 2064 | CommonTree typeSpecifierList = (CommonTree) enumContainerType.getChild(0); |
866e5b51 FC |
2065 | |
2066 | /* Parse it and get the corresponding declaration */ | |
94c255ef | 2067 | IDeclaration decl = parseTypeSpecifierList(typeSpecifierList); |
866e5b51 FC |
2068 | |
2069 | /* If is is an integer, return it, else throw an error */ | |
2070 | if (decl instanceof IntegerDeclaration) { | |
2071 | return (IntegerDeclaration) decl; | |
2072 | } | |
2073 | throw new ParseException("enum container type must be an integer"); //$NON-NLS-1$ | |
2074 | } | |
2075 | ||
2076 | private VariantDeclaration parseVariant(CommonTree variant) | |
2077 | throws ParseException { | |
866e5b51 FC |
2078 | |
2079 | List<CommonTree> children = variant.getChildren(); | |
2080 | VariantDeclaration variantDeclaration = null; | |
2081 | ||
2082 | boolean hasName = false; | |
2083 | String variantName = null; | |
2084 | ||
2085 | boolean hasBody = false; | |
2086 | CommonTree variantBody = null; | |
2087 | ||
2088 | boolean hasTag = false; | |
2089 | String variantTag = null; | |
2090 | ||
2091 | for (CommonTree child : children) { | |
2092 | switch (child.getType()) { | |
2093 | case CTFParser.VARIANT_NAME: | |
866e5b51 FC |
2094 | |
2095 | hasName = true; | |
2096 | ||
72dbc4ac | 2097 | CommonTree variantNameIdentifier = (CommonTree) child.getChild(0); |
866e5b51 | 2098 | |
866e5b51 FC |
2099 | variantName = variantNameIdentifier.getText(); |
2100 | ||
2101 | break; | |
2102 | case CTFParser.VARIANT_TAG: | |
866e5b51 FC |
2103 | |
2104 | hasTag = true; | |
2105 | ||
72dbc4ac | 2106 | CommonTree variantTagIdentifier = (CommonTree) child.getChild(0); |
866e5b51 | 2107 | |
866e5b51 FC |
2108 | variantTag = variantTagIdentifier.getText(); |
2109 | ||
2110 | break; | |
2111 | case CTFParser.VARIANT_BODY: | |
866e5b51 FC |
2112 | |
2113 | hasBody = true; | |
2114 | ||
2115 | variantBody = child; | |
2116 | ||
2117 | break; | |
2118 | default: | |
4ed7d9c1 | 2119 | throw childTypeError(child); |
866e5b51 FC |
2120 | } |
2121 | } | |
2122 | ||
2123 | if (hasBody) { | |
2124 | /* | |
2125 | * If variant has a name, check if already defined in the current | |
2126 | * scope. | |
2127 | */ | |
2128 | if (hasName | |
2129 | && (getCurrentScope().lookupVariant(variantName) != null)) { | |
2130 | throw new ParseException("variant " + variantName //$NON-NLS-1$ | |
2131 | + " already defined."); //$NON-NLS-1$ | |
2132 | } | |
2133 | ||
2134 | /* Create the declaration */ | |
2135 | variantDeclaration = new VariantDeclaration(); | |
2136 | ||
2137 | /* Parse the body */ | |
3ba65808 | 2138 | parseVariantBody(variantBody, variantDeclaration, variantName); |
866e5b51 FC |
2139 | |
2140 | /* If variant has name, add it to the current scope. */ | |
2141 | if (hasName) { | |
2142 | getCurrentScope().registerVariant(variantName, | |
2143 | variantDeclaration); | |
2144 | } | |
3ba65808 | 2145 | } else /* !hasBody */ { |
866e5b51 FC |
2146 | if (hasName) { |
2147 | /* Name and !body */ | |
2148 | ||
2149 | /* Lookup the name in the current scope. */ | |
2c053b6e | 2150 | variantDeclaration = getCurrentScope().lookupVariantRecursive( |
866e5b51 FC |
2151 | variantName); |
2152 | ||
2153 | /* | |
2154 | * If not found, it means that a struct with such name has not | |
2155 | * been defined | |
2156 | */ | |
2157 | if (variantDeclaration == null) { | |
2158 | throw new ParseException("variant " + variantName //$NON-NLS-1$ | |
2159 | + " is not defined"); //$NON-NLS-1$ | |
2160 | } | |
2161 | } else { | |
2162 | /* !Name and !body */ | |
2163 | ||
2164 | /* We can't do anything with that. */ | |
2165 | throw new ParseException("variant with no name and no body"); //$NON-NLS-1$ | |
2166 | } | |
2167 | } | |
2168 | ||
2169 | if (hasTag) { | |
2170 | variantDeclaration.setTag(variantTag); | |
816fde81 MK |
2171 | |
2172 | IDeclaration decl = getCurrentScope().lookupIdentifierRecursive(variantTag); | |
2173 | if (decl == null) { | |
2174 | throw new ParseException("Variant tag not found: " + variantTag); //$NON-NLS-1$ | |
2175 | } | |
2176 | if (!(decl instanceof EnumDeclaration)) { | |
2177 | throw new ParseException("Variant tag must be an enum: " + variantTag); //$NON-NLS-1$ | |
2178 | } | |
2179 | EnumDeclaration tagDecl = (EnumDeclaration) decl; | |
3de23137 | 2180 | Set<String> intersection = new HashSet<>(tagDecl.getLabels()); |
816fde81 MK |
2181 | intersection.retainAll(variantDeclaration.getFields().keySet()); |
2182 | if (intersection.isEmpty()) { | |
2183 | throw new ParseException("Variant contains no values of the tag, impossible to use: " + variantName); //$NON-NLS-1$ | |
2184 | } | |
866e5b51 FC |
2185 | } |
2186 | ||
866e5b51 FC |
2187 | return variantDeclaration; |
2188 | } | |
2189 | ||
2190 | private void parseVariantBody(CommonTree variantBody, | |
3ba65808 | 2191 | VariantDeclaration variantDeclaration, @Nullable String variantName) throws ParseException { |
866e5b51 FC |
2192 | |
2193 | List<CommonTree> variantDeclarations = variantBody.getChildren(); | |
866e5b51 | 2194 | |
3ba65808 | 2195 | pushNamedScope(variantName, MetadataStrings.VARIANT); |
866e5b51 FC |
2196 | |
2197 | for (CommonTree declarationNode : variantDeclarations) { | |
2198 | switch (declarationNode.getType()) { | |
2199 | case CTFParser.TYPEALIAS: | |
2200 | parseTypealias(declarationNode); | |
2201 | break; | |
2202 | case CTFParser.TYPEDEF: | |
2203 | parseTypedef(declarationNode); | |
2204 | break; | |
2205 | case CTFParser.SV_DECLARATION: | |
2206 | parseVariantDeclaration(declarationNode, variantDeclaration); | |
2207 | break; | |
2208 | default: | |
4ed7d9c1 | 2209 | throw childTypeError(declarationNode); |
866e5b51 FC |
2210 | } |
2211 | } | |
2212 | ||
2213 | popScope(); | |
2214 | } | |
2215 | ||
2216 | private void parseVariantDeclaration(CommonTree declaration, | |
2217 | VariantDeclaration variant) throws ParseException { | |
866e5b51 | 2218 | |
866e5b51 | 2219 | /* Get the type specifier list node */ |
72dbc4ac | 2220 | CommonTree typeSpecifierListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST); |
866e5b51 FC |
2221 | |
2222 | /* Get the type declarator list node */ | |
72dbc4ac | 2223 | CommonTree typeDeclaratorListNode = (CommonTree) declaration.getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST); |
866e5b51 FC |
2224 | |
2225 | /* Get the type declarator list */ | |
72dbc4ac | 2226 | List<CommonTree> typeDeclaratorList = typeDeclaratorListNode.getChildren(); |
866e5b51 FC |
2227 | |
2228 | /* | |
2229 | * For each type declarator, parse the declaration and add a field to | |
2230 | * the variant | |
2231 | */ | |
2232 | for (CommonTree typeDeclaratorNode : typeDeclaratorList) { | |
866e5b51 FC |
2233 | |
2234 | StringBuilder identifierSB = new StringBuilder(); | |
2235 | ||
2236 | IDeclaration decl = parseTypeDeclarator(typeDeclaratorNode, | |
2237 | typeSpecifierListNode, identifierSB); | |
2238 | ||
2c053b6e MK |
2239 | String name = identifierSB.toString(); |
2240 | ||
2241 | if (variant.hasField(name)) { | |
866e5b51 | 2242 | throw new ParseException("variant: duplicate field " //$NON-NLS-1$ |
2c053b6e | 2243 | + name); |
866e5b51 FC |
2244 | } |
2245 | ||
2c053b6e MK |
2246 | getCurrentScope().registerIdentifier(name, decl); |
2247 | ||
2248 | variant.addField(name, decl); | |
866e5b51 FC |
2249 | } |
2250 | } | |
2251 | ||
2252 | /** | |
2253 | * Creates the string representation of a type declaration (type specifier | |
2254 | * list + pointers). | |
2255 | * | |
2256 | * @param typeSpecifierList | |
2257 | * A TYPE_SPECIFIER_LIST node. | |
2258 | * @param pointers | |
2259 | * A list of POINTER nodes. | |
2260 | * @return The string representation. | |
2261 | * @throws ParseException | |
2262 | */ | |
2263 | private static String createTypeDeclarationString( | |
2264 | CommonTree typeSpecifierList, List<CommonTree> pointers) | |
3ba65808 | 2265 | throws ParseException { |
866e5b51 FC |
2266 | StringBuilder sb = new StringBuilder(); |
2267 | ||
2268 | createTypeSpecifierListString(typeSpecifierList, sb); | |
2269 | createPointerListString(pointers, sb); | |
2270 | ||
2271 | return sb.toString(); | |
2272 | } | |
2273 | ||
2274 | /** | |
2275 | * Creates the string representation of a list of type specifiers. | |
2276 | * | |
2277 | * @param typeSpecifierList | |
2278 | * A TYPE_SPECIFIER_LIST node. | |
2279 | * @param sb | |
2280 | * A StringBuilder to which will be appended the string. | |
2281 | * @throws ParseException | |
2282 | */ | |
2283 | private static void createTypeSpecifierListString( | |
2284 | CommonTree typeSpecifierList, StringBuilder sb) | |
3ba65808 | 2285 | throws ParseException { |
866e5b51 FC |
2286 | |
2287 | List<CommonTree> children = typeSpecifierList.getChildren(); | |
866e5b51 FC |
2288 | |
2289 | boolean firstItem = true; | |
2290 | ||
2291 | for (CommonTree child : children) { | |
2292 | if (!firstItem) { | |
2293 | sb.append(' '); | |
2294 | ||
2295 | } | |
2296 | ||
2297 | firstItem = false; | |
2298 | ||
2299 | /* Append the string that represents this type specifier. */ | |
2300 | createTypeSpecifierString(child, sb); | |
2301 | } | |
2302 | } | |
2303 | ||
2304 | /** | |
2305 | * Creates the string representation of a type specifier. | |
2306 | * | |
2307 | * @param typeSpecifier | |
2308 | * A TYPE_SPECIFIER node. | |
2309 | * @param sb | |
2310 | * A StringBuilder to which will be appended the string. | |
2311 | * @throws ParseException | |
2312 | */ | |
2313 | private static void createTypeSpecifierString(CommonTree typeSpecifier, | |
2314 | StringBuilder sb) throws ParseException { | |
2315 | switch (typeSpecifier.getType()) { | |
2316 | case CTFParser.FLOATTOK: | |
2317 | case CTFParser.INTTOK: | |
2318 | case CTFParser.LONGTOK: | |
2319 | case CTFParser.SHORTTOK: | |
2320 | case CTFParser.SIGNEDTOK: | |
2321 | case CTFParser.UNSIGNEDTOK: | |
2322 | case CTFParser.CHARTOK: | |
2323 | case CTFParser.DOUBLETOK: | |
2324 | case CTFParser.VOIDTOK: | |
2325 | case CTFParser.BOOLTOK: | |
2326 | case CTFParser.COMPLEXTOK: | |
2327 | case CTFParser.IMAGINARYTOK: | |
2328 | case CTFParser.CONSTTOK: | |
2329 | case CTFParser.IDENTIFIER: | |
2330 | sb.append(typeSpecifier.getText()); | |
2331 | break; | |
2332 | case CTFParser.STRUCT: { | |
72dbc4ac | 2333 | CommonTree structName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.STRUCT_NAME); |
866e5b51 | 2334 | if (structName == null) { |
2c053b6e | 2335 | throw new ParseException("nameless struct found in createTypeSpecifierString"); //$NON-NLS-1$ |
866e5b51 | 2336 | } |
866e5b51 | 2337 | |
72dbc4ac | 2338 | CommonTree structNameIdentifier = (CommonTree) structName.getChild(0); |
866e5b51 FC |
2339 | |
2340 | sb.append(structNameIdentifier.getText()); | |
2341 | break; | |
2342 | } | |
2343 | case CTFParser.VARIANT: { | |
72dbc4ac | 2344 | CommonTree variantName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.VARIANT_NAME); |
866e5b51 | 2345 | if (variantName == null) { |
2c053b6e | 2346 | throw new ParseException("nameless variant found in createTypeSpecifierString"); //$NON-NLS-1$ |
866e5b51 | 2347 | } |
866e5b51 | 2348 | |
72dbc4ac | 2349 | CommonTree variantNameIdentifier = (CommonTree) variantName.getChild(0); |
866e5b51 FC |
2350 | |
2351 | sb.append(variantNameIdentifier.getText()); | |
2352 | break; | |
2353 | } | |
2354 | case CTFParser.ENUM: { | |
72dbc4ac | 2355 | CommonTree enumName = (CommonTree) typeSpecifier.getFirstChildWithType(CTFParser.ENUM_NAME); |
866e5b51 | 2356 | if (enumName == null) { |
2c053b6e | 2357 | throw new ParseException("nameless enum found in createTypeSpecifierString"); //$NON-NLS-1$ |
866e5b51 | 2358 | } |
866e5b51 FC |
2359 | |
2360 | CommonTree enumNameIdentifier = (CommonTree) enumName.getChild(0); | |
866e5b51 FC |
2361 | |
2362 | sb.append(enumNameIdentifier.getText()); | |
2363 | break; | |
2364 | } | |
2365 | case CTFParser.FLOATING_POINT: | |
2366 | case CTFParser.INTEGER: | |
2367 | case CTFParser.STRING: | |
2c053b6e | 2368 | throw new ParseException("CTF type found in createTypeSpecifierString"); //$NON-NLS-1$ |
866e5b51 | 2369 | default: |
4ed7d9c1 | 2370 | throw childTypeError(typeSpecifier); |
866e5b51 FC |
2371 | } |
2372 | } | |
2373 | ||
2374 | /** | |
2375 | * Creates the string representation of a list of pointers. | |
2376 | * | |
2377 | * @param pointerList | |
2378 | * A list of pointer nodes. If pointerList is null, this function | |
2379 | * does nothing. | |
2380 | * @param sb | |
2381 | * A stringbuilder to which will be appended the string. | |
2382 | */ | |
2383 | private static void createPointerListString(List<CommonTree> pointerList, | |
2384 | StringBuilder sb) { | |
2385 | if (pointerList == null) { | |
2386 | return; | |
2387 | } | |
2388 | ||
2389 | for (CommonTree pointer : pointerList) { | |
866e5b51 FC |
2390 | |
2391 | sb.append(" *"); //$NON-NLS-1$ | |
2392 | if (pointer.getChildCount() > 0) { | |
866e5b51 FC |
2393 | |
2394 | sb.append(" const"); //$NON-NLS-1$ | |
2395 | } | |
2396 | } | |
2397 | } | |
2398 | ||
866e5b51 FC |
2399 | /** |
2400 | * @param node | |
2401 | * The node to check. | |
2402 | * @return True if the given node is an unary string. | |
2403 | */ | |
2404 | private static boolean isUnaryString(CommonTree node) { | |
4311ac8b MAL |
2405 | return ((node.getType() == CTFParser.UNARY_EXPRESSION_STRING)); |
2406 | } | |
2407 | ||
2408 | /** | |
2409 | * @param node | |
2410 | * The node to check. | |
2c053b6e MK |
2411 | * @return True if the given node is any type of unary string (no quotes, |
2412 | * quotes, etc). | |
4311ac8b MAL |
2413 | */ |
2414 | private static boolean isAnyUnaryString(CommonTree node) { | |
2c053b6e | 2415 | return ((node.getType() == CTFParser.UNARY_EXPRESSION_STRING) || (node.getType() == CTFParser.UNARY_EXPRESSION_STRING_QUOTES)); |
866e5b51 FC |
2416 | } |
2417 | ||
2418 | /** | |
2419 | * @param node | |
2420 | * The node to check. | |
2421 | * @return True if the given node is an unary integer. | |
2422 | */ | |
2423 | private static boolean isUnaryInteger(CommonTree node) { | |
72dbc4ac | 2424 | return ((node.getType() == CTFParser.UNARY_EXPRESSION_DEC) || |
2c053b6e | 2425 | (node.getType() == CTFParser.UNARY_EXPRESSION_HEX) || (node.getType() == CTFParser.UNARY_EXPRESSION_OCT)); |
866e5b51 FC |
2426 | } |
2427 | ||
2428 | /** | |
2429 | * Parses a unary string node and return the string value. | |
2430 | * | |
2431 | * @param unaryString | |
2432 | * The unary string node to parse (type UNARY_EXPRESSION_STRING | |
2433 | * or UNARY_EXPRESSION_STRING_QUOTES). | |
2434 | * @return The string value. | |
2435 | */ | |
2436 | /* | |
2437 | * It would be really nice to remove the quotes earlier, such as in the | |
2438 | * parser. | |
2439 | */ | |
2440 | private static String parseUnaryString(CommonTree unaryString) { | |
866e5b51 | 2441 | |
866e5b51 | 2442 | CommonTree value = (CommonTree) unaryString.getChild(0); |
8d90cd62 MK |
2443 | if (value.getType() == CTFParser.UNARY_EXPRESSION_STRING) { |
2444 | value = (CommonTree) value.getChild(0); | |
2445 | } | |
866e5b51 FC |
2446 | String strval = value.getText(); |
2447 | ||
2448 | /* Remove quotes */ | |
2449 | if (unaryString.getType() == CTFParser.UNARY_EXPRESSION_STRING_QUOTES) { | |
2450 | strval = strval.substring(1, strval.length() - 1); | |
2451 | } | |
2452 | ||
2453 | return strval; | |
2454 | } | |
2455 | ||
2456 | /** | |
2457 | * Parses an unary integer (dec, hex or oct). | |
2458 | * | |
2459 | * @param unaryInteger | |
2460 | * An unary integer node. | |
2461 | * @return The integer value. | |
58129ff7 MK |
2462 | * @throws ParseException |
2463 | * on an invalid integer format ("bob" for example) | |
866e5b51 | 2464 | */ |
a94410d9 | 2465 | private static long parseUnaryInteger(CommonTree unaryInteger) throws ParseException { |
866e5b51 FC |
2466 | |
2467 | List<CommonTree> children = unaryInteger.getChildren(); | |
2468 | CommonTree value = children.get(0); | |
2469 | String strval = value.getText(); | |
2470 | ||
2471 | long intval; | |
a94410d9 | 2472 | try { |
ab98db9a | 2473 | intval = Long.decode(strval); |
a94410d9 | 2474 | } catch (NumberFormatException e) { |
466f6d95 | 2475 | throw new ParseException("Invalid integer format: " + strval, e); //$NON-NLS-1$ |
866e5b51 | 2476 | } |
4311ac8b | 2477 | |
866e5b51 FC |
2478 | /* The rest of children are sign */ |
2479 | if ((children.size() % 2) == 0) { | |
2480 | return -intval; | |
2481 | } | |
2482 | return intval; | |
2483 | } | |
2484 | ||
2485 | private static long getMajorOrMinor(CommonTree rightNode) | |
2486 | throws ParseException { | |
866e5b51 FC |
2487 | |
2488 | CommonTree firstChild = (CommonTree) rightNode.getChild(0); | |
2489 | ||
2490 | if (isUnaryInteger(firstChild)) { | |
2491 | if (rightNode.getChildCount() > 1) { | |
2492 | throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$ | |
2493 | } | |
2494 | ||
2495 | long m = parseUnaryInteger(firstChild); | |
2496 | ||
2497 | if (m < 0) { | |
2498 | throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$ | |
2499 | } | |
2500 | ||
2501 | return m; | |
2502 | } | |
2503 | throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$ | |
2504 | } | |
2505 | ||
2506 | private static UUID getUUID(CommonTree rightNode) throws ParseException { | |
866e5b51 FC |
2507 | |
2508 | CommonTree firstChild = (CommonTree) rightNode.getChild(0); | |
2509 | ||
4311ac8b | 2510 | if (isAnyUnaryString(firstChild)) { |
866e5b51 FC |
2511 | if (rightNode.getChildCount() > 1) { |
2512 | throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$ | |
2513 | } | |
2514 | ||
2515 | String uuidstr = parseUnaryString(firstChild); | |
2516 | ||
2517 | try { | |
0594c61c | 2518 | return UUID.fromString(uuidstr); |
866e5b51 | 2519 | } catch (IllegalArgumentException e) { |
466f6d95 | 2520 | throw new ParseException("Invalid format for UUID", e); //$NON-NLS-1$ |
866e5b51 FC |
2521 | } |
2522 | } | |
2523 | throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$ | |
2524 | } | |
2525 | ||
2526 | /** | |
2527 | * Gets the value of a "signed" integer attribute. | |
2528 | * | |
2529 | * @param rightNode | |
2530 | * A CTF_RIGHT node. | |
2531 | * @return The "signed" value as a boolean. | |
2532 | * @throws ParseException | |
2533 | */ | |
2534 | private static boolean getSigned(CommonTree rightNode) | |
2535 | throws ParseException { | |
866e5b51 FC |
2536 | |
2537 | boolean ret = false; | |
2538 | CommonTree firstChild = (CommonTree) rightNode.getChild(0); | |
2539 | ||
2540 | if (isUnaryString(firstChild)) { | |
2541 | String strval = concatenateUnaryStrings(rightNode.getChildren()); | |
2542 | ||
fafc36a7 AM |
2543 | if (strval.equals(MetadataStrings.TRUE) |
2544 | || strval.equals(MetadataStrings.TRUE2)) { | |
866e5b51 | 2545 | ret = true; |
fafc36a7 AM |
2546 | } else if (strval.equals(MetadataStrings.FALSE) |
2547 | || strval.equals(MetadataStrings.FALSE2)) { | |
866e5b51 FC |
2548 | ret = false; |
2549 | } else { | |
2550 | throw new ParseException("Invalid boolean value " //$NON-NLS-1$ | |
2551 | + firstChild.getChild(0).getText()); | |
2552 | } | |
2553 | } else if (isUnaryInteger(firstChild)) { | |
2554 | /* Happens if the value is something like "1234.hello" */ | |
2555 | if (rightNode.getChildCount() > 1) { | |
2556 | throw new ParseException("Invalid boolean value"); //$NON-NLS-1$ | |
2557 | } | |
2558 | ||
2559 | long intval = parseUnaryInteger(firstChild); | |
2560 | ||
2561 | if (intval == 1) { | |
2562 | ret = true; | |
2563 | } else if (intval == 0) { | |
2564 | ret = false; | |
2565 | } else { | |
2566 | throw new ParseException("Invalid boolean value " //$NON-NLS-1$ | |
2567 | + firstChild.getChild(0).getText()); | |
2568 | } | |
2569 | } else { | |
2570 | throw new ParseException(); | |
2571 | } | |
2572 | ||
2573 | return ret; | |
2574 | } | |
2575 | ||
2576 | /** | |
2577 | * Gets the value of a "byte_order" integer attribute. | |
2578 | * | |
2579 | * @param rightNode | |
2580 | * A CTF_RIGHT node. | |
2581 | * @return The "byte_order" value. | |
2582 | * @throws ParseException | |
2583 | */ | |
2584 | private ByteOrder getByteOrder(CommonTree rightNode) throws ParseException { | |
866e5b51 FC |
2585 | |
2586 | CommonTree firstChild = (CommonTree) rightNode.getChild(0); | |
2587 | ||
2588 | if (isUnaryString(firstChild)) { | |
2589 | String strval = concatenateUnaryStrings(rightNode.getChildren()); | |
2590 | ||
fafc36a7 | 2591 | if (strval.equals(MetadataStrings.LE)) { |
866e5b51 | 2592 | return ByteOrder.LITTLE_ENDIAN; |
fafc36a7 AM |
2593 | } else if (strval.equals(MetadataStrings.BE) |
2594 | || strval.equals(MetadataStrings.NETWORK)) { | |
866e5b51 | 2595 | return ByteOrder.BIG_ENDIAN; |
fafc36a7 | 2596 | } else if (strval.equals(MetadataStrings.NATIVE)) { |
9226cfc5 | 2597 | return fTrace.getByteOrder(); |
866e5b51 FC |
2598 | } else { |
2599 | throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$ | |
2600 | } | |
2601 | } | |
2602 | throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$ | |
2603 | } | |
2604 | ||
2605 | /** | |
2606 | * Determines if the given value is a valid alignment value. | |
2607 | * | |
2608 | * @param alignment | |
2609 | * The value to check. | |
2610 | * @return True if it is valid. | |
2611 | */ | |
2612 | private static boolean isValidAlignment(long alignment) { | |
2613 | return !((alignment <= 0) || ((alignment & (alignment - 1)) != 0)); | |
2614 | } | |
2615 | ||
2616 | /** | |
2617 | * Gets the value of a "size" integer attribute. | |
2618 | * | |
2619 | * @param rightNode | |
2620 | * A CTF_RIGHT node. | |
2621 | * @return The "size" value. | |
2622 | * @throws ParseException | |
2623 | */ | |
2624 | private static long getSize(CommonTree rightNode) throws ParseException { | |
866e5b51 FC |
2625 | |
2626 | CommonTree firstChild = (CommonTree) rightNode.getChild(0); | |
2627 | ||
2628 | if (isUnaryInteger(firstChild)) { | |
2629 | if (rightNode.getChildCount() > 1) { | |
2630 | throw new ParseException("Invalid value for size"); //$NON-NLS-1$ | |
2631 | } | |
2632 | ||
2633 | long size = parseUnaryInteger(firstChild); | |
2634 | ||
2635 | if (size < 1) { | |
2636 | throw new ParseException("Invalid value for size"); //$NON-NLS-1$ | |
2637 | } | |
2638 | ||
2639 | return size; | |
2640 | } | |
2641 | throw new ParseException("Invalid value for size"); //$NON-NLS-1$ | |
2642 | } | |
2643 | ||
2644 | /** | |
2645 | * Gets the value of a "align" integer or struct attribute. | |
2646 | * | |
2647 | * @param node | |
2648 | * A CTF_RIGHT node or directly an unary integer. | |
2649 | * @return The align value. | |
2650 | * @throws ParseException | |
2651 | */ | |
2652 | private static long getAlignment(CommonTree node) throws ParseException { | |
866e5b51 FC |
2653 | |
2654 | /* | |
2655 | * If a CTF_RIGHT node was passed, call getAlignment with the first | |
2656 | * child | |
2657 | */ | |
2658 | if (node.getType() == CTFParser.CTF_RIGHT) { | |
2659 | if (node.getChildCount() > 1) { | |
2660 | throw new ParseException("Invalid alignment value"); //$NON-NLS-1$ | |
2661 | } | |
2662 | ||
2663 | return getAlignment((CommonTree) node.getChild(0)); | |
2664 | } else if (isUnaryInteger(node)) { | |
2665 | long alignment = parseUnaryInteger(node); | |
2666 | ||
2667 | if (!isValidAlignment(alignment)) { | |
2668 | throw new ParseException("Invalid value for alignment : " //$NON-NLS-1$ | |
2669 | + alignment); | |
2670 | } | |
2671 | ||
2672 | return alignment; | |
2673 | } | |
2674 | throw new ParseException("Invalid value for alignment"); //$NON-NLS-1$ | |
2675 | } | |
2676 | ||
2677 | /** | |
2678 | * Gets the value of a "base" integer attribute. | |
2679 | * | |
2680 | * @param rightNode | |
2681 | * An CTF_RIGHT node. | |
2682 | * @return The "base" value. | |
2683 | * @throws ParseException | |
2684 | */ | |
2685 | private static int getBase(CommonTree rightNode) throws ParseException { | |
866e5b51 FC |
2686 | |
2687 | CommonTree firstChild = (CommonTree) rightNode.getChild(0); | |
2688 | ||
2689 | if (isUnaryInteger(firstChild)) { | |
2690 | if (rightNode.getChildCount() > 1) { | |
2691 | throw new ParseException("invalid base value"); //$NON-NLS-1$ | |
2692 | } | |
2693 | ||
2694 | long intval = parseUnaryInteger(firstChild); | |
466f6d95 MK |
2695 | if ((intval == INTEGER_BASE_2) || (intval == INTEGER_BASE_8) || (intval == INTEGER_BASE_10) |
2696 | || (intval == INTEGER_BASE_16)) { | |
866e5b51 FC |
2697 | return (int) intval; |
2698 | } | |
2699 | throw new ParseException("Invalid value for base"); //$NON-NLS-1$ | |
2700 | } else if (isUnaryString(firstChild)) { | |
f068c622 MK |
2701 | switch (concatenateUnaryStrings(rightNode.getChildren())) { |
2702 | case MetadataStrings.DECIMAL: | |
2703 | case MetadataStrings.DEC: | |
2704 | case MetadataStrings.DEC_CTE: | |
2705 | case MetadataStrings.INT_MOD: | |
2706 | case MetadataStrings.UNSIGNED_CTE: | |
466f6d95 | 2707 | return INTEGER_BASE_10; |
f068c622 MK |
2708 | case MetadataStrings.HEXADECIMAL: |
2709 | case MetadataStrings.HEX: | |
2710 | case MetadataStrings.X: | |
2711 | case MetadataStrings.X2: | |
2712 | case MetadataStrings.POINTER: | |
466f6d95 | 2713 | return INTEGER_BASE_16; |
f068c622 MK |
2714 | case MetadataStrings.OCT: |
2715 | case MetadataStrings.OCTAL: | |
2716 | case MetadataStrings.OCTAL_CTE: | |
466f6d95 | 2717 | return INTEGER_BASE_8; |
f068c622 MK |
2718 | case MetadataStrings.BIN: |
2719 | case MetadataStrings.BINARY: | |
466f6d95 | 2720 | return INTEGER_BASE_2; |
f068c622 | 2721 | default: |
866e5b51 FC |
2722 | throw new ParseException("Invalid value for base"); //$NON-NLS-1$ |
2723 | } | |
2724 | } else { | |
2725 | throw new ParseException("invalid value for base"); //$NON-NLS-1$ | |
2726 | } | |
2727 | } | |
2728 | ||
2729 | /** | |
2730 | * Gets the value of an "encoding" integer attribute. | |
2731 | * | |
2732 | * @param rightNode | |
2733 | * A CTF_RIGHT node. | |
2734 | * @return The "encoding" value. | |
2735 | * @throws ParseException | |
2736 | */ | |
a4fa4e36 | 2737 | @NonNull |
866e5b51 FC |
2738 | private static Encoding getEncoding(CommonTree rightNode) |
2739 | throws ParseException { | |
866e5b51 FC |
2740 | |
2741 | CommonTree firstChild = (CommonTree) rightNode.getChild(0); | |
2742 | ||
2743 | if (isUnaryString(firstChild)) { | |
2744 | String strval = concatenateUnaryStrings(rightNode.getChildren()); | |
2745 | ||
fafc36a7 | 2746 | if (strval.equals(MetadataStrings.UTF8)) { |
866e5b51 | 2747 | return Encoding.UTF8; |
fafc36a7 | 2748 | } else if (strval.equals(MetadataStrings.ASCII)) { |
866e5b51 | 2749 | return Encoding.ASCII; |
fafc36a7 | 2750 | } else if (strval.equals(MetadataStrings.NONE)) { |
866e5b51 FC |
2751 | return Encoding.NONE; |
2752 | } else { | |
2753 | throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$ | |
2754 | } | |
2755 | } | |
2756 | throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$ | |
2757 | } | |
2758 | ||
2759 | private static long getStreamID(CommonTree rightNode) throws ParseException { | |
866e5b51 FC |
2760 | |
2761 | CommonTree firstChild = (CommonTree) rightNode.getChild(0); | |
2762 | ||
2763 | if (isUnaryInteger(firstChild)) { | |
2764 | if (rightNode.getChildCount() > 1) { | |
2765 | throw new ParseException("invalid value for stream id"); //$NON-NLS-1$ | |
2766 | } | |
2767 | ||
2768 | long intval = parseUnaryInteger(firstChild); | |
2769 | ||
2770 | return intval; | |
2771 | } | |
2772 | throw new ParseException("invalid value for stream id"); //$NON-NLS-1$ | |
2773 | } | |
2774 | ||
2775 | private static String getEventName(CommonTree rightNode) | |
2776 | throws ParseException { | |
866e5b51 FC |
2777 | |
2778 | CommonTree firstChild = (CommonTree) rightNode.getChild(0); | |
2779 | ||
4311ac8b | 2780 | if (isAnyUnaryString(firstChild)) { |
866e5b51 FC |
2781 | String str = concatenateUnaryStrings(rightNode.getChildren()); |
2782 | ||
2783 | return str; | |
2784 | } | |
2785 | throw new ParseException("invalid value for event name"); //$NON-NLS-1$ | |
2786 | } | |
2787 | ||
2788 | private static long getEventID(CommonTree rightNode) throws ParseException { | |
866e5b51 FC |
2789 | |
2790 | CommonTree firstChild = (CommonTree) rightNode.getChild(0); | |
2791 | ||
2792 | if (isUnaryInteger(firstChild)) { | |
2793 | if (rightNode.getChildCount() > 1) { | |
2794 | throw new ParseException("invalid value for event id"); //$NON-NLS-1$ | |
2795 | } | |
2796 | ||
2797 | long intval = parseUnaryInteger(firstChild); | |
6c7592e1 MK |
2798 | if (intval > Integer.MAX_VALUE) { |
2799 | throw new ParseException("Event id larger than int.maxvalue, something is amiss"); //$NON-NLS-1$ | |
2800 | } | |
866e5b51 FC |
2801 | return intval; |
2802 | } | |
2803 | throw new ParseException("invalid value for event id"); //$NON-NLS-1$ | |
2804 | } | |
2805 | ||
2806 | /** | |
2807 | * Concatenates a list of unary strings separated by arrows (->) or dots. | |
2808 | * | |
2809 | * @param strings | |
2810 | * A list, first element being an unary string, subsequent | |
2811 | * elements being ARROW or DOT nodes with unary strings as child. | |
2812 | * @return The string representation of the unary string chain. | |
2813 | */ | |
2814 | private static String concatenateUnaryStrings(List<CommonTree> strings) { | |
866e5b51 FC |
2815 | |
2816 | StringBuilder sb = new StringBuilder(); | |
2817 | ||
2818 | CommonTree first = strings.get(0); | |
2819 | sb.append(parseUnaryString(first)); | |
2820 | ||
2821 | boolean isFirst = true; | |
2822 | ||
2823 | for (CommonTree ref : strings) { | |
2824 | if (isFirst) { | |
2825 | isFirst = false; | |
2826 | continue; | |
2827 | } | |
2828 | ||
866e5b51 FC |
2829 | CommonTree id = (CommonTree) ref.getChild(0); |
2830 | ||
2831 | if (ref.getType() == CTFParser.ARROW) { | |
2832 | sb.append("->"); //$NON-NLS-1$ | |
2833 | } else { /* DOT */ | |
2834 | sb.append('.'); | |
2835 | } | |
2836 | ||
2837 | sb.append(parseUnaryString(id)); | |
2838 | } | |
2839 | ||
2840 | return sb.toString(); | |
2841 | } | |
2842 | ||
2843 | /** | |
2844 | * Throws a ParseException stating that the parent-child relation between | |
2845 | * the given node and its parent is not valid. It means that the shape of | |
2846 | * the AST is unexpected. | |
2847 | * | |
2848 | * @param child | |
2849 | * The invalid child node. | |
4ed7d9c1 | 2850 | * @return ParseException with details |
866e5b51 | 2851 | */ |
4ed7d9c1 | 2852 | private static ParseException childTypeError(CommonTree child) { |
866e5b51 FC |
2853 | CommonTree parent = (CommonTree) child.getParent(); |
2854 | String error = "Parent " + CTFParser.tokenNames[parent.getType()] //$NON-NLS-1$ | |
2855 | + " can't have a child of type " //$NON-NLS-1$ | |
2856 | + CTFParser.tokenNames[child.getType()] + "."; //$NON-NLS-1$ | |
2857 | ||
4ed7d9c1 | 2858 | return new ParseException(error); |
866e5b51 FC |
2859 | } |
2860 | ||
2861 | // ------------------------------------------------------------------------ | |
2862 | // Scope management | |
2863 | // ------------------------------------------------------------------------ | |
2864 | ||
2865 | /** | |
2866 | * Adds a new declaration scope on the top of the scope stack. | |
2867 | */ | |
3ba65808 | 2868 | private void pushScope(String name) { |
8d90cd62 | 2869 | fScope = new DeclarationScope(getCurrentScope(), name); |
866e5b51 FC |
2870 | } |
2871 | ||
2872 | /** | |
2873 | * Removes the top declaration scope from the scope stack. | |
2874 | */ | |
2875 | private void popScope() { | |
8d90cd62 | 2876 | fScope = getCurrentScope().getParentScope(); |
866e5b51 FC |
2877 | } |
2878 | ||
3ba65808 MK |
2879 | private void pushNamedScope(@Nullable String name, String defaultName) { |
2880 | pushScope(name == null ? defaultName : name); | |
2881 | } | |
2882 | ||
866e5b51 FC |
2883 | /** |
2884 | * Returns the current declaration scope. | |
2885 | * | |
2886 | * @return The current declaration scope. | |
2887 | */ | |
2888 | private DeclarationScope getCurrentScope() { | |
9226cfc5 | 2889 | return fScope; |
866e5b51 FC |
2890 | } |
2891 | ||
2892 | } |