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