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