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