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