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