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