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