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