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