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