Fix bug when tracefile is not aligned. Now supports exotic architectures.
[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;
53047a66 31import org.eclipse.linuxtools.ctf.core.event.types.FloatDeclaration;
866e5b51
FC
32import org.eclipse.linuxtools.ctf.core.event.types.IDeclaration;
33import org.eclipse.linuxtools.ctf.core.event.types.IntegerDeclaration;
34import org.eclipse.linuxtools.ctf.core.event.types.SequenceDeclaration;
35import org.eclipse.linuxtools.ctf.core.event.types.StringDeclaration;
36import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration;
37import org.eclipse.linuxtools.ctf.core.event.types.VariantDeclaration;
38import org.eclipse.linuxtools.ctf.core.trace.CTFTrace;
866e5b51 39import org.eclipse.linuxtools.ctf.parser.CTFParser;
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 722 event.setFields(fields);
53047a66
MK
723 }
724 else if (left.equals("loglevel")){ //$NON-NLS-1$
866e5b51 725
53047a66
MK
726 long logLevel = parseUnaryInteger((CommonTree) rightNode.getChild(0)) ;
727 event.setLogLevel(logLevel);
866e5b51
FC
728 } else {
729 throw new ParseException("Unknown event attribute : " + left); //$NON-NLS-1$
730 }
731 }
732
733 /**
734 * Parses a declaration at the root level.
735 *
736 * @param declaration
737 * The declaration subtree.
738 * @throws ParseException
739 */
740 private void parseRootDeclaration(CommonTree declaration)
741 throws ParseException {
742 assert (declaration.getType() == CTFParser.DECLARATION);
743
744 List<CommonTree> children = declaration.getChildren();
745 assert (children != null);
746
747 for (CommonTree child : children) {
748 switch (child.getType()) {
749 case CTFParser.TYPEDEF:
750 parseTypedef(child);
751 break;
752 case CTFParser.TYPEALIAS:
753 parseTypealias(child);
754 break;
755 case CTFParser.TYPE_SPECIFIER_LIST:
756 parseTypeSpecifierList(child, null);
757 break;
758 default:
759 childTypeError(child);
760 }
761 }
762 }
763
764 /**
765 * Parses a typealias node. It parses the target, the alias, and registers
766 * the type in the current scope.
767 *
768 * @param typealias
769 * A TYPEALIAS node.
770 * @throws ParseException
771 */
772 private void parseTypealias(CommonTree typealias) throws ParseException {
773 assert (typealias.getType() == CTFParser.TYPEALIAS);
774
775 List<CommonTree> children = typealias.getChildren();
776 assert (children != null);
777
778 CommonTree target = null;
779 CommonTree alias = null;
780
781 for (CommonTree child : children) {
782 switch (child.getType()) {
783 case CTFParser.TYPEALIAS_TARGET:
784 assert (target == null);
785 target = child;
786 break;
787 case CTFParser.TYPEALIAS_ALIAS:
788 assert (alias == null);
789 alias = child;
790 break;
791 default:
792 childTypeError(child);
793 break;
794 }
795 }
796
797 assert (target != null);
798 assert (alias != null);
799
800 IDeclaration targetDeclaration = parseTypealiasTarget(target);
801
802 if (targetDeclaration instanceof VariantDeclaration) {
803 if (((VariantDeclaration) targetDeclaration).isTagged()) {
804 throw new ParseException(
805 "Typealias of untagged variant is not permitted"); //$NON-NLS-1$
806 }
807 }
808
809 String aliasString = parseTypealiasAlias(alias);
810
811 getCurrentScope().registerType(aliasString, targetDeclaration);
812 }
813
814 /**
815 * Parses the target part of a typealias and gets the corresponding
816 * declaration.
817 *
818 * @param target
819 * A TYPEALIAS_TARGET node.
820 * @return The corresponding declaration.
821 * @throws ParseException
822 */
823 private IDeclaration parseTypealiasTarget(CommonTree target)
824 throws ParseException {
825 assert (target.getType() == CTFParser.TYPEALIAS_TARGET);
826
827 List<CommonTree> children = target.getChildren();
828 assert (children != null);
829
830 CommonTree typeSpecifierList = null;
831 CommonTree typeDeclaratorList = null;
832 CommonTree typeDeclarator = null;
833 StringBuilder identifierSB = new StringBuilder();
834
835 for (CommonTree child : children) {
836 switch (child.getType()) {
837 case CTFParser.TYPE_SPECIFIER_LIST:
838 assert (typeSpecifierList == null);
839 typeSpecifierList = child;
840 break;
841 case CTFParser.TYPE_DECLARATOR_LIST:
842 assert (typeDeclaratorList == null);
843 typeDeclaratorList = child;
844 break;
845 default:
846 childTypeError(child);
847 break;
848 }
849 }
850
851 assert (typeSpecifierList != null);
852
853 if (typeDeclaratorList != null) {
854 /*
855 * Only allow one declarator
856 *
857 * eg: "typealias uint8_t *, ** := puint8_t;" is not permitted,
858 * otherwise the new type puint8_t would maps to two different
859 * types.
860 */
861 if (typeDeclaratorList.getChildCount() != 1) {
862 throw new ParseException(
863 "Only one type declarator is allowed in the typealias target"); //$NON-NLS-1$
864 }
865
866 typeDeclarator = (CommonTree) typeDeclaratorList.getChild(0);
867 }
868
869 /* Parse the target type and get the declaration */
870 IDeclaration targetDeclaration = parseTypeDeclarator(typeDeclarator,
871 typeSpecifierList, identifierSB);
872
873 /*
874 * We don't allow identifier in the target
875 *
876 * eg: "typealias uint8_t* hello := puint8_t;", the "hello" is not
877 * permitted
878 */
879 if (identifierSB.length() > 0) {
880 throw new ParseException("Identifier (" + identifierSB.toString() //$NON-NLS-1$
881 + ") not expected in the typealias target"); //$NON-NLS-1$
882 }
883
884 return targetDeclaration;
885 }
886
887 /**
888 * Parses the alias part of a typealias. It parses the underlying specifier
889 * list and declarator and creates the string representation that will be
890 * used to register the type.
891 *
892 * @param alias
893 * A TYPEALIAS_ALIAS node.
894 * @return The string representation of the alias.
895 * @throws ParseException
896 */
897 private static String parseTypealiasAlias(CommonTree alias)
898 throws ParseException {
899 assert (alias.getType() == CTFParser.TYPEALIAS_ALIAS);
900
901 List<CommonTree> children = alias.getChildren();
902 assert (children != null);
903
904 CommonTree typeSpecifierList = null;
905 CommonTree typeDeclaratorList = null;
906 CommonTree typeDeclarator = null;
907 List<CommonTree> pointers = new LinkedList<CommonTree>();
908
909 for (CommonTree child : children) {
910 switch (child.getType()) {
911 case CTFParser.TYPE_SPECIFIER_LIST:
912 assert (typeSpecifierList == null);
913 typeSpecifierList = child;
914 break;
915 case CTFParser.TYPE_DECLARATOR_LIST:
916 assert (typeDeclaratorList == null);
917 typeDeclaratorList = child;
918 break;
919 default:
920 childTypeError(child);
921 break;
922 }
923 }
924
925 /* If there is a type declarator list, extract the pointers */
926 if (typeDeclaratorList != null) {
927 /*
928 * Only allow one declarator
929 *
930 * eg: "typealias uint8_t := puint8_t *, **;" is not permitted.
931 */
932 if (typeDeclaratorList.getChildCount() != 1) {
933 throw new ParseException(
934 "Only one type declarator is allowed in the typealias alias"); //$NON-NLS-1$
935 }
936
937 typeDeclarator = (CommonTree) typeDeclaratorList.getChild(0);
938
939 List<CommonTree> typeDeclaratorChildren = typeDeclarator
940 .getChildren();
941 assert (typeDeclaratorChildren != null);
942
943 for (CommonTree child : typeDeclaratorChildren) {
944 switch (child.getType()) {
945 case CTFParser.POINTER:
946 pointers.add(child);
947 break;
948 case CTFParser.IDENTIFIER:
949 throw new ParseException("Identifier (" + child.getText() //$NON-NLS-1$
950 + ") not expected in the typealias target"); //$NON-NLS-1$
951 /* break; */
952 default:
953 childTypeError(child);
954 break;
955 }
956 }
957 }
958
959 return createTypeDeclarationString(typeSpecifierList, pointers);
960 }
961
962 /**
963 * Parses a typedef node. This creates and registers a new declaration for
964 * each declarator found in the typedef.
965 *
966 * @param typedef
967 * A TYPEDEF node.
968 * @throws ParseException
969 * If there is an error creating the declaration.
970 */
971 private void parseTypedef(CommonTree typedef) throws ParseException {
972 assert (typedef.getType() == CTFParser.TYPEDEF);
973
974 CommonTree typeDeclaratorListNode = (CommonTree) typedef
975 .getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
976 assert (typeDeclaratorListNode != null);
977
978 CommonTree typeSpecifierListNode = (CommonTree) typedef
979 .getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
980 assert (typeSpecifierListNode != null);
981
982 List<CommonTree> typeDeclaratorList = typeDeclaratorListNode
983 .getChildren();
984 assert (typeDeclaratorList != null);
985
986 for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
987 StringBuilder identifierSB = new StringBuilder();
988
989 IDeclaration type_declaration = parseTypeDeclarator(
990 typeDeclaratorNode, typeSpecifierListNode, identifierSB);
991
992 if (type_declaration instanceof VariantDeclaration) {
993 if (((VariantDeclaration) type_declaration).isTagged()) {
994 throw new ParseException(
995 "Typealias of untagged variant is not permitted"); //$NON-NLS-1$
996 }
997 }
998
999 getCurrentScope().registerType(identifierSB.toString(),
1000 type_declaration);
1001 }
1002 }
1003
1004 /**
1005 * Parses a pair type declarator / type specifier list and returns the
1006 * corresponding declaration. If it is present, it also writes the
1007 * identifier of the declarator in the given {@link StringBuilder}.
1008 *
1009 * @param typeDeclarator
1010 * A TYPE_DECLARATOR node.
1011 * @param typeSpecifierList
1012 * A TYPE_SPECIFIER_LIST node.
1013 * @param identifierSB
1014 * A StringBuilder that will receive the identifier found in the
1015 * declarator.
1016 * @return The corresponding declaration.
1017 * @throws ParseException
1018 * If there is an error finding or creating the declaration.
1019 */
1020 private IDeclaration parseTypeDeclarator(CommonTree typeDeclarator,
1021 CommonTree typeSpecifierList, StringBuilder identifierSB)
1022 throws ParseException {
1023 if (typeDeclarator != null) {
1024 assert (typeDeclarator.getType() == CTFParser.TYPE_DECLARATOR);
1025 }
1026 assert (typeSpecifierList.getType() == CTFParser.TYPE_SPECIFIER_LIST);
1027
1028 IDeclaration declaration = null;
1029 List<CommonTree> children = null;
1030 List<CommonTree> pointers = new LinkedList<CommonTree>();
1031 List<CommonTree> lengths = new LinkedList<CommonTree>();
1032 CommonTree identifier = null;
1033
1034 /* Separate the tokens by type */
1035 if (typeDeclarator != null) {
1036 children = typeDeclarator.getChildren();
1037 assert (children != null);
1038 for (CommonTree child : children) {
1039
1040 switch (child.getType()) {
1041 case CTFParser.POINTER:
1042 pointers.add(child);
1043 break;
1044 case CTFParser.IDENTIFIER:
1045 assert (identifier == null);
1046 identifier = child;
1047 break;
1048 case CTFParser.LENGTH:
1049 lengths.add(child);
1050 break;
1051 default:
1052 childTypeError(child);
1053 break;
1054 }
1055 }
1056
1057 }
1058
1059 /*
1060 * Parse the type specifier list, which is the "base" type. For example,
1061 * it would be int in int a[3][len].
1062 */
1063 declaration = parseTypeSpecifierList(typeSpecifierList, pointers);
1064
1065 /*
1066 * Each length subscript means that we must create a nested array or
1067 * sequence. For example, int a[3][len] means that we have an array of 3
1068 * (sequences of length 'len' of (int)).
1069 */
284fdee8 1070 if (lengths.size() > 0 ) {
866e5b51
FC
1071 /* We begin at the end */
1072 Collections.reverse(lengths);
1073
1074 for (CommonTree length : lengths) {
1075 /*
1076 * By looking at the first expression, we can determine whether
1077 * it is an array or a sequence.
1078 */
1079 List<CommonTree> lengthChildren = length.getChildren();
1080 assert (lengthChildren != null);
1081
1082 CommonTree first = lengthChildren.get(0);
1083 if (isUnaryInteger(first)) {
1084 /* Array */
1085 int arrayLength = (int) parseUnaryInteger(first);
1086
1087 if (arrayLength < 1) {
1088 throw new ParseException("Array length is negative"); //$NON-NLS-1$
1089 }
1090
1091 /* Create the array declaration. */
1092 declaration = new ArrayDeclaration(arrayLength, declaration);
1093 } else if (isUnaryString(first)) {
1094 /* Sequence */
1095 String lengthName = concatenateUnaryStrings(lengthChildren);
1096
1097 /* Create the sequence declaration. */
1098 declaration = new SequenceDeclaration(lengthName,
1099 declaration);
1100 } else {
1101 childTypeError(first);
1102 }
1103 }
1104 }
1105
1106 if (identifier != null) {
1107 identifierSB.append(identifier.getText());
1108 }
1109
1110 return declaration;
1111 }
1112
1113 /**
1114 * Parses a type specifier list and returns the corresponding declaration.
1115 *
1116 * @param typeSpecifierList
1117 * A TYPE_SPECIFIER_LIST node.
1118 * @param pointerList
1119 * A list of POINTER nodes that apply to the specified type.
1120 * @return The corresponding declaration.
1121 * @throws ParseException
1122 * If the type has not been defined or if there is an error
1123 * creating the declaration.
1124 */
1125 private IDeclaration parseTypeSpecifierList(CommonTree typeSpecifierList,
1126 List<CommonTree> pointerList) throws ParseException {
1127 assert (typeSpecifierList.getType() == CTFParser.TYPE_SPECIFIER_LIST);
1128 IDeclaration declaration = null;
1129
1130 /*
1131 * By looking at the first element of the type specifier list, we can
1132 * determine which type it belongs to.
1133 */
1134 CommonTree firstChild = (CommonTree) typeSpecifierList.getChild(0);
1135 assert (firstChild != null); /* grammar */
1136
1137 switch (firstChild.getType()) {
1138 case CTFParser.FLOATING_POINT:
53047a66
MK
1139// Activator
1140// .getDefault()
1141// .log("parseTypeSpecifierList: floating_point not implemented yet"); //$NON-NLS-1$
1142 declaration = parseFloat(firstChild);
866e5b51
FC
1143 break;
1144 case CTFParser.INTEGER:
1145 declaration = parseInteger(firstChild);
1146 break;
1147 case CTFParser.STRING:
1148 declaration = parseString(firstChild);
1149 break;
1150 case CTFParser.STRUCT:
1151 declaration = parseStruct(firstChild);
1152 break;
1153 case CTFParser.VARIANT:
1154 declaration = parseVariant(firstChild);
1155 break;
1156 case CTFParser.ENUM:
1157 declaration = parseEnum(firstChild);
1158 break;
1159 case CTFParser.IDENTIFIER:
1160 case CTFParser.FLOATTOK:
1161 case CTFParser.INTTOK:
1162 case CTFParser.LONGTOK:
1163 case CTFParser.SHORTTOK:
1164 case CTFParser.SIGNEDTOK:
1165 case CTFParser.UNSIGNEDTOK:
1166 case CTFParser.CHARTOK:
1167 case CTFParser.DOUBLETOK:
1168 case CTFParser.VOIDTOK:
1169 case CTFParser.BOOLTOK:
1170 case CTFParser.COMPLEXTOK:
1171 case CTFParser.IMAGINARYTOK:
1172 declaration = parseTypeDeclaration(typeSpecifierList, pointerList);
1173 break;
1174 default:
1175 childTypeError(firstChild);
1176 }
1177
1178 assert (declaration != null);
1179 return declaration;
1180 }
1181
53047a66
MK
1182 private IDeclaration parseFloat(CommonTree floatingPoint) throws ParseException {
1183 assert (floatingPoint.getType() == CTFParser.INTEGER);
1184
1185 List<CommonTree> children = floatingPoint.getChildren();
1186
1187 /*
1188 * If the integer has no attributes, then it is missing the size
1189 * attribute which is required
1190 */
1191 if (children == null) {
1192 throw new ParseException("float: missing size attribute"); //$NON-NLS-1$
1193 }
1194
1195 /* The return value */
1196 FloatDeclaration floatDeclaration = null;
1197 ByteOrder byteOrder = trace.getByteOrder();
1198 long alignment = 0;
1199 int base = 2;
1200 int exponent = 8;
1201 int mantissa = 24;
1202
1203 Encoding encoding = Encoding.NONE;
1204
1205 /* Iterate on all integer children */
1206 for (CommonTree child : children) {
1207 switch (child.getType()) {
1208 case CTFParser.CTF_EXPRESSION_VAL:
1209 /*
1210 * An assignment expression must have 2 children, left and right
1211 */
1212 assert (child.getChildCount() == 2);
1213
1214 CommonTree leftNode = (CommonTree) child.getChild(0);
1215 assert (leftNode.getType() == CTFParser.CTF_LEFT);
1216 CommonTree rightNode = (CommonTree) child.getChild(1);
1217 assert (rightNode.getType() == CTFParser.CTF_RIGHT);
1218
1219 List<CommonTree> leftStrings = leftNode.getChildren();
1220 assert (leftStrings != null);
1221
1222 if (!isUnaryString(leftStrings.get(0))) {
1223 throw new ParseException(
1224 "Left side of ctf expression must be a string"); //$NON-NLS-1$
1225 }
1226 String left = concatenateUnaryStrings(leftStrings);
1227
1228 if (left.equals("exp_dig")) { //$NON-NLS-1$
1229 exponent = (int) parseUnaryInteger((CommonTree) rightNode.getChild(0));
1230 } else if (left.equals("byte_order")) { //$NON-NLS-1$
1231 byteOrder = getByteOrder(rightNode);
1232 } else if (left.equals("mant_dig")) { //$NON-NLS-1$
1233 mantissa = (int) parseUnaryInteger((CommonTree) rightNode.getChild(0));
1234 } else if (left.equals("align")) { //$NON-NLS-1$
1235 alignment = getAlignment(rightNode);
1236 } else {
1237 throw new ParseException("Float: unknown attribute " + left); //$NON-NLS-1$
1238 }
1239
1240 break;
1241 default:
1242 childTypeError(child);
1243 break;
1244 }
1245 }
1246 int size = mantissa + exponent;
1247 if (size == 0) {
1248 throw new ParseException("Float missing size attribute"); //$NON-NLS-1$
1249 }
1250
1251 if (alignment == 0) {
1252 if ((size % 8) == 0) {
1253 alignment = 1;
1254 } else {
1255 alignment = 8;
1256 }
1257 }
1258
fd74e6c1 1259 floatDeclaration = new FloatDeclaration(exponent, mantissa, byteOrder, encoding, alignment);
53047a66
MK
1260
1261 assert (floatDeclaration != null);
1262 return floatDeclaration;
1263
1264 }
1265
866e5b51
FC
1266 /**
1267 * Parses a type specifier list as a user-declared type.
1268 *
1269 * @param typeSpecifierList
1270 * A TYPE_SPECIFIER_LIST node containing a user-declared type.
1271 * @param pointerList
1272 * A list of POINTER nodes that apply to the type specified in
1273 * typeSpecifierList.
1274 * @return The corresponding declaration.
1275 * @throws ParseException
1276 * If the type does not exist (has not been found).
1277 */
1278 private IDeclaration parseTypeDeclaration(CommonTree typeSpecifierList,
1279 List<CommonTree> pointerList) throws ParseException {
1280 /* Create the string representation of the type declaration */
1281 String typeStringRepresentation = createTypeDeclarationString(
1282 typeSpecifierList, pointerList);
1283
1284 /* Use the string representation to search the type in the current scope */
1285 IDeclaration decl = getCurrentScope().rlookupType(
1286 typeStringRepresentation);
1287
1288 if (decl == null) {
1289 throw new ParseException("Type " + typeStringRepresentation //$NON-NLS-1$
1290 + " has not been defined."); //$NON-NLS-1$
1291 }
1292
1293 return decl;
1294 }
1295
1296 /**
1297 * Parses an integer declaration node.
1298 *
1299 * @param integer
1300 * An INTEGER node.
1301 * @return The corresponding integer declaration.
1302 * @throws ParseException
1303 */
1304 private IntegerDeclaration parseInteger(CommonTree integer)
1305 throws ParseException {
1306 assert (integer.getType() == CTFParser.INTEGER);
1307
1308 List<CommonTree> children = integer.getChildren();
1309
1310 /*
1311 * If the integer has no attributes, then it is missing the size
1312 * attribute which is required
1313 */
1314 if (children == null) {
1315 throw new ParseException("integer: missing size attribute"); //$NON-NLS-1$
1316 }
1317
1318 /* The return value */
1319 IntegerDeclaration integerDeclaration = null;
1320 boolean signed = false;
1321 ByteOrder byteOrder = trace.getByteOrder();
1322 long size = 0;
1323 long alignment = 0;
1324 int base = 10;
284fdee8 1325 String clock = null;
866e5b51
FC
1326
1327 Encoding encoding = Encoding.NONE;
1328
1329 /* Iterate on all integer children */
1330 for (CommonTree child : children) {
1331 switch (child.getType()) {
1332 case CTFParser.CTF_EXPRESSION_VAL:
1333 /*
1334 * An assignment expression must have 2 children, left and right
1335 */
1336 assert (child.getChildCount() == 2);
1337
1338 CommonTree leftNode = (CommonTree) child.getChild(0);
1339 assert (leftNode.getType() == CTFParser.CTF_LEFT);
1340 CommonTree rightNode = (CommonTree) child.getChild(1);
1341 assert (rightNode.getType() == CTFParser.CTF_RIGHT);
1342
1343 List<CommonTree> leftStrings = leftNode.getChildren();
1344 assert (leftStrings != null);
1345
1346 if (!isUnaryString(leftStrings.get(0))) {
1347 throw new ParseException(
1348 "Left side of ctf expression must be a string"); //$NON-NLS-1$
1349 }
1350 String left = concatenateUnaryStrings(leftStrings);
1351
1352 if (left.equals("signed")) { //$NON-NLS-1$
1353 signed = getSigned(rightNode);
1354 } else if (left.equals("byte_order")) { //$NON-NLS-1$
1355 byteOrder = getByteOrder(rightNode);
1356 } else if (left.equals("size")) { //$NON-NLS-1$
1357 size = getSize(rightNode);
1358 } else if (left.equals("align")) { //$NON-NLS-1$
1359 alignment = getAlignment(rightNode);
1360 } else if (left.equals("base")) { //$NON-NLS-1$
1361 base = getBase(rightNode);
1362 } else if (left.equals("encoding")) { //$NON-NLS-1$
1363 encoding = getEncoding(rightNode);
1364 } else if (left.equals("map")) { //$NON-NLS-1$
1365 clock = getClock(rightNode);
1366 } else {
1367 throw new ParseException("Integer: unknown attribute " + left); //$NON-NLS-1$
1368 }
1369
1370 break;
1371 default:
1372 childTypeError(child);
1373 break;
1374 }
1375 }
1376
1377 if (size == 0) {
1378 throw new ParseException("Integer missing size attribute"); //$NON-NLS-1$
1379 }
1380
1381 if (alignment == 0) {
1382 if ((size % 8) == 0) {
1383 alignment = 1;
1384 } else {
1385 alignment = 8;
1386 }
1387 }
1388
1389 integerDeclaration = new IntegerDeclaration((int) size, signed, base,
fd74e6c1 1390 byteOrder, encoding, clock, alignment);
866e5b51
FC
1391
1392 assert (integerDeclaration != null);
1393 return integerDeclaration;
1394 }
1395
284fdee8 1396 private static String getClock(CommonTree rightNode) {
866e5b51
FC
1397 return rightNode.getChild(1).getChild(0).getChild(0).getText();
1398 }
1399
1400 private static StringDeclaration parseString(CommonTree string)
1401 throws ParseException {
1402 assert (string.getType() == CTFParser.STRING);
1403
1404 List<CommonTree> children = string.getChildren();
1405 StringDeclaration stringDeclaration = null;
1406
1407 if (children == null) {
1408 stringDeclaration = new StringDeclaration();
1409 } else {
1410 Encoding encoding = Encoding.UTF8;
1411 for (CommonTree child : children) {
1412 switch (child.getType()) {
1413 case CTFParser.CTF_EXPRESSION_VAL:
1414 /*
1415 * An assignment expression must have 2 children, left and
1416 * right
1417 */
1418 assert (child.getChildCount() == 2);
1419
1420 CommonTree leftNode = (CommonTree) child.getChild(0);
1421 assert (leftNode.getType() == CTFParser.CTF_LEFT);
1422 CommonTree rightNode = (CommonTree) child.getChild(1);
1423 assert (rightNode.getType() == CTFParser.CTF_RIGHT);
1424
1425 List<CommonTree> leftStrings = leftNode.getChildren();
1426 assert (leftStrings != null);
1427
1428 if (!isUnaryString(leftStrings.get(0))) {
1429 throw new ParseException(
1430 "Left side of ctf expression must be a string"); //$NON-NLS-1$
1431 }
1432 String left = concatenateUnaryStrings(leftStrings);
1433
1434 if (left.equals("encoding")) { //$NON-NLS-1$
1435 encoding = getEncoding(rightNode);
1436 } else {
1437 throw new ParseException("String: unknown attribute " //$NON-NLS-1$
1438 + left);
1439 }
1440
1441 break;
1442 default:
1443 childTypeError(child);
1444 break;
1445 }
1446 }
1447
1448 stringDeclaration = new StringDeclaration(encoding);
1449 }
1450
1451 return stringDeclaration;
1452 }
1453
1454 /**
1455 * Parses a struct declaration and returns the corresponding declaration.
1456 *
1457 * @param struct
1458 * An STRUCT node.
1459 * @return The corresponding struct declaration.
1460 * @throws ParseException
1461 */
1462 private StructDeclaration parseStruct(CommonTree struct)
1463 throws ParseException {
1464 assert (struct.getType() == CTFParser.STRUCT);
1465
1466 List<CommonTree> children = struct.getChildren();
1467 assert (children != null);
1468
1469 /* The return value */
1470 StructDeclaration structDeclaration = null;
1471
1472 /* Name */
1473 String structName = null;
1474 boolean hasName = false;
1475
1476 /* Body */
1477 CommonTree structBody = null;
1478 boolean hasBody = false;
1479
1480 /* Align */
1481 long structAlign = 0;
1482
1483 /* Loop on all children and identify what we have to work with. */
1484 for (CommonTree child : children) {
1485 switch (child.getType()) {
1486 case CTFParser.STRUCT_NAME: {
1487 hasName = true;
1488
1489 assert (child.getChildCount() == 1);
1490 CommonTree structNameIdentifier = (CommonTree) child
1491 .getChild(0);
1492
1493 assert (structNameIdentifier.getType() == CTFParser.IDENTIFIER);
1494 structName = structNameIdentifier.getText();
1495
1496 break;
1497 }
1498 case CTFParser.STRUCT_BODY: {
1499 hasBody = true;
1500
1501 structBody = child;
1502
1503 break;
1504 }
1505 case CTFParser.ALIGN: {
1506 assert (child.getChildCount() == 1);
1507 CommonTree structAlignExpression = (CommonTree) child
1508 .getChild(0);
1509
1510 structAlign = getAlignment(structAlignExpression);
1511
1512 break;
1513 }
1514 default:
1515 childTypeError(child);
1516
1517 break;
1518 }
1519 }
1520
1521 /*
1522 * If a struct has just a body and no name (just like the song,
1523 * "A Struct With No Name" by America (sorry for that...)), it's a
1524 * definition of a new type, so we create the type declaration and
1525 * return it. We can't add it to the declaration scope since there is no
1526 * name, but that's what we want because it won't be possible to use it
1527 * again to declare another field.
1528 *
1529 * If it has just a name, we look it up in the declaration scope and
1530 * return the associated declaration. If it is not found in the
1531 * declaration scope, it means that a struct with that name has not been
1532 * declared, which is an error.
1533 *
1534 * If it has both, then we create the type declaration and register it
1535 * to the current scope.
1536 *
1537 * If it has none, then what are we doing here ?
1538 */
1539 if (hasBody) {
1540 /*
1541 * If struct has a name, check if already defined in the current
1542 * scope.
1543 */
1544 if (hasName && (getCurrentScope().lookupStruct(structName) != null)) {
1545 throw new ParseException("struct " + structName //$NON-NLS-1$
1546 + " already defined."); //$NON-NLS-1$
1547 }
1548
1549 /* Create the declaration */
1550 structDeclaration = new StructDeclaration(structAlign);
1551
1552 /* Parse the body */
1553 parseStructBody(structBody, structDeclaration);
fd74e6c1
MK
1554 long maxFieldAlign = -1;
1555 for( IDeclaration field : structDeclaration.getFields().values())
1556 {
1557 maxFieldAlign = Math.max(maxFieldAlign, field.getAlignment());
1558 }
1559 structDeclaration.setMinAlign(maxFieldAlign);
866e5b51
FC
1560
1561 /* If struct has name, add it to the current scope. */
1562 if (hasName) {
1563 getCurrentScope().registerStruct(structName, structDeclaration);
1564 }
1565 } else /* !hasBody */{
1566 if (hasName) {
1567 /* Name and !body */
1568
1569 /* Lookup the name in the current scope. */
1570 structDeclaration = getCurrentScope().rlookupStruct(structName);
1571
1572 /*
1573 * If not found, it means that a struct with such name has not
1574 * been defined
1575 */
1576 if (structDeclaration == null) {
1577 throw new ParseException("struct " + structName //$NON-NLS-1$
1578 + " is not defined"); //$NON-NLS-1$
1579 }
1580 } else {
1581 /* !Name and !body */
1582
1583 /* We can't do anything with that. */
1584 throw new ParseException("struct with no name and no body"); //$NON-NLS-1$
1585 }
1586 }
1587
1588 assert (structDeclaration != null);
1589 return structDeclaration;
1590 }
1591
1592 /**
1593 * Parses a struct body, adding the fields to specified structure
1594 * declaration.
1595 *
1596 * @param structBody
1597 * A STRUCT_BODY node.
1598 * @param structDeclaration
1599 * The struct declaration.
1600 * @throws ParseException
1601 */
1602 private void parseStructBody(CommonTree structBody,
1603 StructDeclaration structDeclaration) throws ParseException {
1604 assert (structBody.getType() == CTFParser.STRUCT_BODY);
1605
1606 List<CommonTree> structDeclarations = structBody.getChildren();
1607
1608 /*
1609 * If structDeclaration is null, structBody has no children and the
1610 * struct body is empty.
1611 */
1612 if (structDeclarations != null) {
1613 pushScope();
1614
1615 for (CommonTree declarationNode : structDeclarations) {
1616 switch (declarationNode.getType()) {
1617 case CTFParser.TYPEALIAS:
1618 parseTypealias(declarationNode);
1619 break;
1620 case CTFParser.TYPEDEF:
1621 parseTypedef(declarationNode);
1622 break;
1623 case CTFParser.SV_DECLARATION:
1624 parseStructDeclaration(declarationNode, structDeclaration);
1625 break;
1626 default:
1627 childTypeError(declarationNode);
1628 break;
1629 }
1630 }
1631 popScope();
1632 }
1633 }
1634
1635 /**
1636 * Parses a declaration found in a struct.
1637 *
1638 * @param declaration
1639 * A SV_DECLARATION node.
1640 * @param struct
1641 * A struct declaration. (I know, little name clash here...)
1642 * @throws ParseException
1643 */
1644 private void parseStructDeclaration(CommonTree declaration,
1645 StructDeclaration struct) throws ParseException {
1646 assert (declaration.getType() == CTFParser.SV_DECLARATION);
1647
1648 List<CommonTree> children = declaration.getChildren();
1649 assert (children != null);
1650
1651 /* Get the type specifier list node */
1652 CommonTree typeSpecifierListNode = (CommonTree) declaration
1653 .getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
1654 assert (typeSpecifierListNode != null);
1655
1656 /* Get the type declarator list node */
1657 CommonTree typeDeclaratorListNode = (CommonTree) declaration
1658 .getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
1659 assert (typeDeclaratorListNode != null);
1660
1661 /* Get the type declarator list */
1662 List<CommonTree> typeDeclaratorList = typeDeclaratorListNode
1663 .getChildren();
1664 assert (typeDeclaratorList != null);
1665
1666 /*
1667 * For each type declarator, parse the declaration and add a field to
1668 * the struct
1669 */
1670 for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
1671 assert (typeDeclaratorNode.getType() == CTFParser.TYPE_DECLARATOR);
1672
1673 StringBuilder identifierSB = new StringBuilder();
1674
1675 IDeclaration decl = parseTypeDeclarator(typeDeclaratorNode,
1676 typeSpecifierListNode, identifierSB);
1677 String fieldName = identifierSB.toString();
866e5b51
FC
1678
1679 if (struct.hasField(fieldName)) {
1680 throw new ParseException("struct: duplicate field " //$NON-NLS-1$
1681 + fieldName);
1682 }
1683
1684 struct.addField(fieldName, decl);
1685
1686 }
1687 }
1688
1689 /**
1690 * Parses an enum declaration and returns the corresponding declaration.
1691 *
1692 * @param _enum
1693 * An ENUM node.
1694 * @return The corresponding enum declaration.
1695 * @throws ParseException
1696 */
1697 private EnumDeclaration parseEnum(CommonTree _enum) throws ParseException {
1698 assert (_enum.getType() == CTFParser.ENUM);
1699
1700 List<CommonTree> children = _enum.getChildren();
1701 assert (children != null);
1702
1703 /* The return value */
1704 EnumDeclaration enumDeclaration = null;
1705
1706 /* Name */
1707 String enumName = null;
1708
1709 /* Body */
1710 CommonTree enumBody = null;
1711
1712 /* Container type */
1713 IntegerDeclaration containerTypeDeclaration = null;
1714
1715 /* Loop on all children and identify what we have to work with. */
1716 for (CommonTree child : children) {
1717 switch (child.getType()) {
1718 case CTFParser.ENUM_NAME: {
1719 assert (enumName == null);
1720
1721 assert (child.getChildCount() == 1);
1722 CommonTree enumNameIdentifier = (CommonTree) child.getChild(0);
1723
1724 assert (enumNameIdentifier.getType() == CTFParser.IDENTIFIER);
1725 enumName = enumNameIdentifier.getText();
1726
1727 break;
1728 }
1729 case CTFParser.ENUM_BODY: {
1730 assert (enumBody == null);
1731
1732 enumBody = child;
1733
1734 break;
1735 }
1736 case CTFParser.ENUM_CONTAINER_TYPE: {
1737 assert (containerTypeDeclaration == null);
1738
1739 containerTypeDeclaration = parseEnumContainerType(child);
1740
1741 break;
1742 }
1743 default:
1744 childTypeError(child);
1745 break;
1746 }
1747 }
1748
1749 /*
1750 * If the container type has not been defined explicitly, we assume it
1751 * is "int".
1752 */
1753 if (containerTypeDeclaration == null) {
1754 IDeclaration decl = getCurrentScope().rlookupType("int"); //$NON-NLS-1$
1755
1756 if (decl == null) {
1757 throw new ParseException(
1758 "enum container type implicit and type int not defined"); //$NON-NLS-1$
1759 } else if (!(decl instanceof IntegerDeclaration)) {
1760 throw new ParseException(
1761 "enum container type implicit and type int not an integer"); //$NON-NLS-1$
1762 }
1763
1764 containerTypeDeclaration = (IntegerDeclaration) decl;
1765 }
1766
1767 /*
1768 * If it has a body, it's a new declaration, otherwise it's a reference
1769 * to an existing declaration. Same logic as struct.
1770 */
1771 if (enumBody != null) {
1772 /*
1773 * If enum has a name, check if already defined in the current
1774 * scope.
1775 */
1776 if ((enumName != null)
1777 && (getCurrentScope().lookupEnum(enumName) != null)) {
1778 throw new ParseException("enum " + enumName //$NON-NLS-1$
1779 + " already defined"); //$NON-NLS-1$
1780 }
1781
1782 /* Create the declaration */
1783 enumDeclaration = new EnumDeclaration(containerTypeDeclaration);
1784
1785 /* Parse the body */
1786 parseEnumBody(enumBody, enumDeclaration);
1787
1788 /* If the enum has name, add it to the current scope. */
1789 if (enumName != null) {
1790 getCurrentScope().registerEnum(enumName, enumDeclaration);
1791 }
1792 } else {
1793 if (enumName != null) {
1794 /* Name and !body */
1795
1796 /* Lookup the name in the current scope. */
1797 enumDeclaration = getCurrentScope().rlookupEnum(enumName);
1798
1799 /*
1800 * If not found, it means that an enum with such name has not
1801 * been defined
1802 */
1803 if (enumDeclaration == null) {
1804 throw new ParseException("enum " + enumName //$NON-NLS-1$
1805 + " is not defined"); //$NON-NLS-1$
1806 }
1807 } else {
1808 /* !Name and !body */
1809 throw new ParseException("enum with no name and no body"); //$NON-NLS-1$
1810 }
1811 }
1812
1813 return enumDeclaration;
1814
1815 }
1816
1817 /**
1818 * Parses an enum body, adding the enumerators to the specified enum
1819 * declaration.
1820 *
1821 * @param enumBody
1822 * An ENUM_BODY node.
1823 * @param enumDeclaration
1824 * The enum declaration.
1825 * @throws ParseException
1826 */
1827 private void parseEnumBody(CommonTree enumBody,
1828 EnumDeclaration enumDeclaration) throws ParseException {
1829 assert (enumBody.getType() == CTFParser.ENUM_BODY);
1830
1831 List<CommonTree> enumerators = enumBody.getChildren();
1832 /* enum body can't be empty (unlike struct). */
1833 assert (enumerators != null);
1834
1835 pushScope();
1836
1837 /*
1838 * Start at -1, so that if the first enumrator has no explicit value, it
1839 * will choose 0
1840 */
1841 long lastHigh = -1;
1842
1843 for (CommonTree enumerator : enumerators) {
1844 lastHigh = parseEnumEnumerator(enumerator, enumDeclaration,
1845 lastHigh);
1846 }
1847
1848 popScope();
1849
1850 }
1851
1852 /**
1853 * Parses an enumerator node and adds an enumerator declaration to an
1854 * enumeration declaration.
1855 *
1856 * The high value of the range of the last enumerator is needed in case the
1857 * current enumerator does not specify its value.
1858 *
1859 * @param enumerator
1860 * An ENUM_ENUMERATOR node.
1861 * @param enumDeclaration
1862 * en enumeration declaration to which will be added the
1863 * enumerator.
1864 * @param lastHigh
1865 * The high value of the range of the last enumerator
1866 * @return The high value of the value range of the current enumerator.
1867 * @throws ParseException
1868 */
1869 private static long parseEnumEnumerator(CommonTree enumerator,
1870 EnumDeclaration enumDeclaration, long lastHigh)
1871 throws ParseException {
1872 assert (enumerator.getType() == CTFParser.ENUM_ENUMERATOR);
1873
1874 List<CommonTree> children = enumerator.getChildren();
1875 assert (children != null);
1876
1877 long low = 0, high = 0;
1878 boolean valueSpecified = false;
1879 String label = null;
1880
1881 for (CommonTree child : children) {
1882 if (isUnaryString(child)) {
1883 label = parseUnaryString(child);
1884 } else if (child.getType() == CTFParser.ENUM_VALUE) {
1885 assert (child.getChildCount() == 1);
1886 assert (isUnaryInteger((CommonTree) child.getChild(0)));
1887
1888 valueSpecified = true;
1889
1890 low = parseUnaryInteger((CommonTree) child.getChild(0));
1891 high = low;
1892 } else if (child.getType() == CTFParser.ENUM_VALUE_RANGE) {
1893 assert (child.getChildCount() == 2);
1894 assert (isUnaryInteger((CommonTree) child.getChild(0)));
1895 assert (isUnaryInteger((CommonTree) child.getChild(1)));
1896
1897 valueSpecified = true;
1898
1899 low = parseUnaryInteger((CommonTree) child.getChild(0));
1900 high = parseUnaryInteger((CommonTree) child.getChild(1));
1901 } else {
1902 childTypeError(child);
1903 }
1904 }
1905
1906 assert (label != null);
1907
1908 if (!valueSpecified) {
1909 low = lastHigh + 1;
1910 high = low;
1911 }
1912
1913 if (low > high) {
1914 throw new ParseException("enum low value greater than high value"); //$NON-NLS-1$
1915 }
1916
1917 if (!enumDeclaration.add(low, high, label)) {
1918 throw new ParseException("enum declarator values overlap."); //$NON-NLS-1$
1919 }
1920
1921 return high;
1922 }
1923
1924 /**
1925 * Parses an enum container type node and returns the corresponding integer
1926 * type.
1927 *
1928 * @param enumContainerType
1929 * An ENUM_CONTAINER_TYPE node.
1930 * @return An integer declaration corresponding to the container type.
1931 * @throws ParseException
1932 * If the type does not parse correctly or if it is not an
1933 * integer type.
1934 */
1935 private IntegerDeclaration parseEnumContainerType(
1936 CommonTree enumContainerType) throws ParseException {
1937 assert (enumContainerType.getType() == CTFParser.ENUM_CONTAINER_TYPE);
1938
1939 /* Get the child, which should be a type specifier list */
1940 assert (enumContainerType.getChildCount() == 1);
1941 CommonTree typeSpecifierList = (CommonTree) enumContainerType
1942 .getChild(0);
1943
1944 /* Parse it and get the corresponding declaration */
1945 IDeclaration decl = parseTypeSpecifierList(typeSpecifierList, null);
1946
1947 /* If is is an integer, return it, else throw an error */
1948 if (decl instanceof IntegerDeclaration) {
1949 return (IntegerDeclaration) decl;
1950 }
1951 throw new ParseException("enum container type must be an integer"); //$NON-NLS-1$
1952 }
1953
1954 private VariantDeclaration parseVariant(CommonTree variant)
1955 throws ParseException {
1956 assert (variant.getType() == CTFParser.VARIANT);
1957
1958 List<CommonTree> children = variant.getChildren();
1959 VariantDeclaration variantDeclaration = null;
1960
1961 boolean hasName = false;
1962 String variantName = null;
1963
1964 boolean hasBody = false;
1965 CommonTree variantBody = null;
1966
1967 boolean hasTag = false;
1968 String variantTag = null;
1969
1970 for (CommonTree child : children) {
1971 switch (child.getType()) {
1972 case CTFParser.VARIANT_NAME:
1973 assert (variantName == null);
1974
1975 hasName = true;
1976
1977 assert (child.getChildCount() == 1);
1978 CommonTree variantNameIdentifier = (CommonTree) child
1979 .getChild(0);
1980
1981 assert (variantNameIdentifier.getType() == CTFParser.IDENTIFIER);
1982 variantName = variantNameIdentifier.getText();
1983
1984 break;
1985 case CTFParser.VARIANT_TAG:
1986 assert (variantTag == null);
1987
1988 hasTag = true;
1989
1990 assert (child.getChildCount() == 1);
1991 CommonTree variantTagIdentifier = (CommonTree) child
1992 .getChild(0);
1993
1994 assert (variantTagIdentifier.getType() == CTFParser.IDENTIFIER);
1995 variantTag = variantTagIdentifier.getText();
1996
1997 break;
1998 case CTFParser.VARIANT_BODY:
1999 assert (variantBody == null);
2000
2001 hasBody = true;
2002
2003 variantBody = child;
2004
2005 break;
2006 default:
2007 childTypeError(child);
2008 break;
2009 }
2010 }
2011
2012 if (hasBody) {
2013 /*
2014 * If variant has a name, check if already defined in the current
2015 * scope.
2016 */
2017 if (hasName
2018 && (getCurrentScope().lookupVariant(variantName) != null)) {
2019 throw new ParseException("variant " + variantName //$NON-NLS-1$
2020 + " already defined."); //$NON-NLS-1$
2021 }
2022
2023 /* Create the declaration */
2024 variantDeclaration = new VariantDeclaration();
2025
2026 /* Parse the body */
2027 parseVariantBody(variantBody, variantDeclaration);
2028
2029 /* If variant has name, add it to the current scope. */
2030 if (hasName) {
2031 getCurrentScope().registerVariant(variantName,
2032 variantDeclaration);
2033 }
2034 } else /* !hasBody */{
2035 if (hasName) {
2036 /* Name and !body */
2037
2038 /* Lookup the name in the current scope. */
2039 variantDeclaration = getCurrentScope().rlookupVariant(
2040 variantName);
2041
2042 /*
2043 * If not found, it means that a struct with such name has not
2044 * been defined
2045 */
2046 if (variantDeclaration == null) {
2047 throw new ParseException("variant " + variantName //$NON-NLS-1$
2048 + " is not defined"); //$NON-NLS-1$
2049 }
2050 } else {
2051 /* !Name and !body */
2052
2053 /* We can't do anything with that. */
2054 throw new ParseException("variant with no name and no body"); //$NON-NLS-1$
2055 }
2056 }
2057
2058 if (hasTag) {
2059 variantDeclaration.setTag(variantTag);
2060 }
2061
2062 assert (variantDeclaration != null);
2063 return variantDeclaration;
2064 }
2065
2066 private void parseVariantBody(CommonTree variantBody,
2067 VariantDeclaration variantDeclaration) throws ParseException {
2068 assert (variantBody.getType() == CTFParser.VARIANT_BODY);
2069
2070 List<CommonTree> variantDeclarations = variantBody.getChildren();
2071 assert (variantDeclarations != null);
2072
2073 pushScope();
2074
2075 for (CommonTree declarationNode : variantDeclarations) {
2076 switch (declarationNode.getType()) {
2077 case CTFParser.TYPEALIAS:
2078 parseTypealias(declarationNode);
2079 break;
2080 case CTFParser.TYPEDEF:
2081 parseTypedef(declarationNode);
2082 break;
2083 case CTFParser.SV_DECLARATION:
2084 parseVariantDeclaration(declarationNode, variantDeclaration);
2085 break;
2086 default:
2087 childTypeError(declarationNode);
2088 break;
2089 }
2090 }
2091
2092 popScope();
2093 }
2094
2095 private void parseVariantDeclaration(CommonTree declaration,
2096 VariantDeclaration variant) throws ParseException {
2097 assert (declaration.getType() == CTFParser.SV_DECLARATION);
2098
2099 List<CommonTree> children = declaration.getChildren();
2100 assert (children != null);
2101
2102 /* Get the type specifier list node */
2103 CommonTree typeSpecifierListNode = (CommonTree) declaration
2104 .getFirstChildWithType(CTFParser.TYPE_SPECIFIER_LIST);
2105 assert (typeSpecifierListNode != null);
2106
2107 /* Get the type declarator list node */
2108 CommonTree typeDeclaratorListNode = (CommonTree) declaration
2109 .getFirstChildWithType(CTFParser.TYPE_DECLARATOR_LIST);
2110 assert (typeDeclaratorListNode != null);
2111
2112 /* Get the type declarator list */
2113 List<CommonTree> typeDeclaratorList = typeDeclaratorListNode
2114 .getChildren();
2115 assert (typeDeclaratorList != null);
2116
2117 /*
2118 * For each type declarator, parse the declaration and add a field to
2119 * the variant
2120 */
2121 for (CommonTree typeDeclaratorNode : typeDeclaratorList) {
2122 assert (typeDeclaratorNode.getType() == CTFParser.TYPE_DECLARATOR);
2123
2124 StringBuilder identifierSB = new StringBuilder();
2125
2126 IDeclaration decl = parseTypeDeclarator(typeDeclaratorNode,
2127 typeSpecifierListNode, identifierSB);
2128
2129 if (variant.hasField(identifierSB.toString())) {
2130 throw new ParseException("variant: duplicate field " //$NON-NLS-1$
2131 + identifierSB.toString());
2132 }
2133
2134 variant.addField(identifierSB.toString(), decl);
2135 }
2136 }
2137
2138 /**
2139 * Creates the string representation of a type declaration (type specifier
2140 * list + pointers).
2141 *
2142 * @param typeSpecifierList
2143 * A TYPE_SPECIFIER_LIST node.
2144 * @param pointers
2145 * A list of POINTER nodes.
2146 * @return The string representation.
2147 * @throws ParseException
2148 */
2149 private static String createTypeDeclarationString(
2150 CommonTree typeSpecifierList, List<CommonTree> pointers)
2151 throws ParseException {
2152 StringBuilder sb = new StringBuilder();
2153
2154 createTypeSpecifierListString(typeSpecifierList, sb);
2155 createPointerListString(pointers, sb);
2156
2157 return sb.toString();
2158 }
2159
2160 /**
2161 * Creates the string representation of a list of type specifiers.
2162 *
2163 * @param typeSpecifierList
2164 * A TYPE_SPECIFIER_LIST node.
2165 * @param sb
2166 * A StringBuilder to which will be appended the string.
2167 * @throws ParseException
2168 */
2169 private static void createTypeSpecifierListString(
2170 CommonTree typeSpecifierList, StringBuilder sb)
2171 throws ParseException {
2172 assert (typeSpecifierList.getType() == CTFParser.TYPE_SPECIFIER_LIST);
2173
2174 List<CommonTree> children = typeSpecifierList.getChildren();
2175 assert (children != null);
2176
2177 boolean firstItem = true;
2178
2179 for (CommonTree child : children) {
2180 if (!firstItem) {
2181 sb.append(' ');
2182
2183 }
2184
2185 firstItem = false;
2186
2187 /* Append the string that represents this type specifier. */
2188 createTypeSpecifierString(child, sb);
2189 }
2190 }
2191
2192 /**
2193 * Creates the string representation of a type specifier.
2194 *
2195 * @param typeSpecifier
2196 * A TYPE_SPECIFIER node.
2197 * @param sb
2198 * A StringBuilder to which will be appended the string.
2199 * @throws ParseException
2200 */
2201 private static void createTypeSpecifierString(CommonTree typeSpecifier,
2202 StringBuilder sb) throws ParseException {
2203 switch (typeSpecifier.getType()) {
2204 case CTFParser.FLOATTOK:
2205 case CTFParser.INTTOK:
2206 case CTFParser.LONGTOK:
2207 case CTFParser.SHORTTOK:
2208 case CTFParser.SIGNEDTOK:
2209 case CTFParser.UNSIGNEDTOK:
2210 case CTFParser.CHARTOK:
2211 case CTFParser.DOUBLETOK:
2212 case CTFParser.VOIDTOK:
2213 case CTFParser.BOOLTOK:
2214 case CTFParser.COMPLEXTOK:
2215 case CTFParser.IMAGINARYTOK:
2216 case CTFParser.CONSTTOK:
2217 case CTFParser.IDENTIFIER:
2218 sb.append(typeSpecifier.getText());
2219 break;
2220 case CTFParser.STRUCT: {
2221 CommonTree structName = (CommonTree) typeSpecifier
2222 .getFirstChildWithType(CTFParser.STRUCT_NAME);
2223 if (structName == null) {
2224 throw new ParseException(
2225 "nameless struct found in createTypeSpecifierString"); //$NON-NLS-1$
2226 }
2227 assert (structName.getChildCount() == 1);
2228
2229 CommonTree structNameIdentifier = (CommonTree) structName
2230 .getChild(0);
2231 assert (structNameIdentifier.getType() == CTFParser.IDENTIFIER);
2232
2233 sb.append(structNameIdentifier.getText());
2234 break;
2235 }
2236 case CTFParser.VARIANT: {
2237 CommonTree variantName = (CommonTree) typeSpecifier
2238 .getFirstChildWithType(CTFParser.VARIANT_NAME);
2239 if (variantName == null) {
2240 throw new ParseException(
2241 "nameless variant found in createTypeSpecifierString"); //$NON-NLS-1$
2242 }
2243 assert (variantName.getChildCount() == 1);
2244
2245 CommonTree variantNameIdentifier = (CommonTree) variantName
2246 .getChild(0);
2247 assert (variantNameIdentifier.getType() == CTFParser.IDENTIFIER);
2248
2249 sb.append(variantNameIdentifier.getText());
2250 break;
2251 }
2252 case CTFParser.ENUM: {
2253 CommonTree enumName = (CommonTree) typeSpecifier
2254 .getFirstChildWithType(CTFParser.ENUM_NAME);
2255 if (enumName == null) {
2256 throw new ParseException(
2257 "nameless enum found in createTypeSpecifierString"); //$NON-NLS-1$
2258 }
2259 assert (enumName.getChildCount() == 1);
2260
2261 CommonTree enumNameIdentifier = (CommonTree) enumName.getChild(0);
2262 assert (enumNameIdentifier.getType() == CTFParser.IDENTIFIER);
2263
2264 sb.append(enumNameIdentifier.getText());
2265 break;
2266 }
2267 case CTFParser.FLOATING_POINT:
2268 case CTFParser.INTEGER:
2269 case CTFParser.STRING:
2270 throw new ParseException(
2271 "CTF type found in createTypeSpecifierString"); //$NON-NLS-1$
2272 /* break; */
2273 default:
2274 childTypeError(typeSpecifier);
2275 break;
2276 }
2277 }
2278
2279 /**
2280 * Creates the string representation of a list of pointers.
2281 *
2282 * @param pointerList
2283 * A list of pointer nodes. If pointerList is null, this function
2284 * does nothing.
2285 * @param sb
2286 * A stringbuilder to which will be appended the string.
2287 */
2288 private static void createPointerListString(List<CommonTree> pointerList,
2289 StringBuilder sb) {
2290 if (pointerList == null) {
2291 return;
2292 }
2293
2294 for (CommonTree pointer : pointerList) {
2295 assert (pointer.getType() == CTFParser.POINTER);
2296
2297 sb.append(" *"); //$NON-NLS-1$
2298 if (pointer.getChildCount() > 0) {
2299 assert (pointer.getChildCount() == 1);
2300 CommonTree constQualifier = (CommonTree) pointer.getChild(0);
2301 assert (constQualifier.getType() == CTFParser.CONSTTOK);
2302
2303 sb.append(" const"); //$NON-NLS-1$
2304 }
2305 }
2306 }
2307
2308 /**
2309 * @param node
2310 * The node to check.
2311 * @return True if the given node is an unary string or unary integer.
2312 */
2313 private static boolean isUnaryExpression(CommonTree node) {
2314 return isUnaryInteger(node) || isUnaryString(node);
2315 }
2316
2317 /**
2318 * @param node
2319 * The node to check.
2320 * @return True if the given node is an unary string.
2321 */
2322 private static boolean isUnaryString(CommonTree node) {
2323 return ((node.getType() == CTFParser.UNARY_EXPRESSION_STRING) || (node
2324 .getType() == CTFParser.UNARY_EXPRESSION_STRING_QUOTES));
2325 }
2326
2327 /**
2328 * @param node
2329 * The node to check.
2330 * @return True if the given node is an unary integer.
2331 */
2332 private static boolean isUnaryInteger(CommonTree node) {
2333 return ((node.getType() == CTFParser.UNARY_EXPRESSION_DEC)
2334 || (node.getType() == CTFParser.UNARY_EXPRESSION_HEX) || (node
2335 .getType() == CTFParser.UNARY_EXPRESSION_OCT));
2336 }
2337
2338 /**
2339 * Parses a unary string node and return the string value.
2340 *
2341 * @param unaryString
2342 * The unary string node to parse (type UNARY_EXPRESSION_STRING
2343 * or UNARY_EXPRESSION_STRING_QUOTES).
2344 * @return The string value.
2345 */
2346 /*
2347 * It would be really nice to remove the quotes earlier, such as in the
2348 * parser.
2349 */
2350 private static String parseUnaryString(CommonTree unaryString) {
2351 assert (isUnaryString(unaryString));
2352
2353 assert (unaryString.getChildCount() == 1);
2354 CommonTree value = (CommonTree) unaryString.getChild(0);
2355 assert (value != null);
2356 String strval = value.getText();
2357
2358 /* Remove quotes */
2359 if (unaryString.getType() == CTFParser.UNARY_EXPRESSION_STRING_QUOTES) {
2360 strval = strval.substring(1, strval.length() - 1);
2361 }
2362
2363 return strval;
2364 }
2365
2366 /**
2367 * Parses an unary integer (dec, hex or oct).
2368 *
2369 * @param unaryInteger
2370 * An unary integer node.
2371 * @return The integer value.
2372 */
2373 private static long parseUnaryInteger(CommonTree unaryInteger) {
2374 assert (isUnaryInteger(unaryInteger));
2375
2376 assert (unaryInteger.getChildCount() >= 1);
2377
2378 List<CommonTree> children = unaryInteger.getChildren();
2379 CommonTree value = children.get(0);
2380 String strval = value.getText();
2381
2382 long intval;
2383
2384 if (unaryInteger.getType() == CTFParser.UNARY_EXPRESSION_DEC) {
2385 intval = Long.parseLong(strval, 10);
2386 } else if (unaryInteger.getType() == CTFParser.UNARY_EXPRESSION_HEX) {
2387 intval = Long.parseLong(strval, 0x10);
2388 } else { /* unaryInteger.getType() == CTFParser.UNARY_EXPRESSION_OCT */
2389 intval = Long.parseLong(strval, 010); // 010 == 0x08 == 8
2390 }
2391
2392 /* The rest of children are sign */
2393 if ((children.size() % 2) == 0) {
2394 return -intval;
2395 }
2396 return intval;
2397 }
2398
2399 private static long getMajorOrMinor(CommonTree rightNode)
2400 throws ParseException {
2401 assert (rightNode.getType() == CTFParser.CTF_RIGHT);
2402 assert (rightNode.getChildCount() > 0);
2403
2404 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2405
2406 if (isUnaryInteger(firstChild)) {
2407 if (rightNode.getChildCount() > 1) {
2408 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2409 }
2410
2411 long m = parseUnaryInteger(firstChild);
2412
2413 if (m < 0) {
2414 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2415 }
2416
2417 return m;
2418 }
2419 throw new ParseException("Invalid value for major/minor"); //$NON-NLS-1$
2420 }
2421
2422 private static UUID getUUID(CommonTree rightNode) throws ParseException {
2423 assert (rightNode.getType() == CTFParser.CTF_RIGHT);
2424 assert (rightNode.getChildCount() > 0);
2425
2426 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2427
2428 if (isUnaryString(firstChild)) {
2429 if (rightNode.getChildCount() > 1) {
2430 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2431 }
2432
2433 String uuidstr = parseUnaryString(firstChild);
2434
2435 try {
2436 UUID uuid = UUID.fromString(uuidstr);
2437 return uuid;
2438 } catch (IllegalArgumentException e) {
2439 throw new ParseException("Invalid format for UUID"); //$NON-NLS-1$
2440 }
2441 }
2442 throw new ParseException("Invalid value for UUID"); //$NON-NLS-1$
2443 }
2444
2445 /**
2446 * Gets the value of a "signed" integer attribute.
2447 *
2448 * @param rightNode
2449 * A CTF_RIGHT node.
2450 * @return The "signed" value as a boolean.
2451 * @throws ParseException
2452 */
2453 private static boolean getSigned(CommonTree rightNode)
2454 throws ParseException {
2455 assert (rightNode.getType() == CTFParser.CTF_RIGHT);
2456 assert (rightNode.getChildCount() > 0);
2457
2458 boolean ret = false;
2459 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2460
2461 if (isUnaryString(firstChild)) {
2462 String strval = concatenateUnaryStrings(rightNode.getChildren());
2463
2464 if (strval.equals("true") || strval.equals("TRUE")) { //$NON-NLS-1$ //$NON-NLS-2$
2465 ret = true;
2466 } else if (strval.equals("false") || strval.equals("FALSE")) { //$NON-NLS-1$ //$NON-NLS-2$
2467 ret = false;
2468 } else {
2469 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2470 + firstChild.getChild(0).getText());
2471 }
2472 } else if (isUnaryInteger(firstChild)) {
2473 /* Happens if the value is something like "1234.hello" */
2474 if (rightNode.getChildCount() > 1) {
2475 throw new ParseException("Invalid boolean value"); //$NON-NLS-1$
2476 }
2477
2478 long intval = parseUnaryInteger(firstChild);
2479
2480 if (intval == 1) {
2481 ret = true;
2482 } else if (intval == 0) {
2483 ret = false;
2484 } else {
2485 throw new ParseException("Invalid boolean value " //$NON-NLS-1$
2486 + firstChild.getChild(0).getText());
2487 }
2488 } else {
2489 throw new ParseException();
2490 }
2491
2492 return ret;
2493 }
2494
2495 /**
2496 * Gets the value of a "byte_order" integer attribute.
2497 *
2498 * @param rightNode
2499 * A CTF_RIGHT node.
2500 * @return The "byte_order" value.
2501 * @throws ParseException
2502 */
2503 private ByteOrder getByteOrder(CommonTree rightNode) throws ParseException {
2504 assert (rightNode.getType() == CTFParser.CTF_RIGHT);
2505 assert (rightNode.getChildCount() > 0);
2506
2507 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2508
2509 if (isUnaryString(firstChild)) {
2510 String strval = concatenateUnaryStrings(rightNode.getChildren());
2511
2512 if (strval.equals("le")) { //$NON-NLS-1$
2513 return ByteOrder.LITTLE_ENDIAN;
2514 } else if (strval.equals("be") || strval.equals("network")) { //$NON-NLS-1$ //$NON-NLS-2$
2515 return ByteOrder.BIG_ENDIAN;
2516 } else if (strval.equals("native")) { //$NON-NLS-1$
2517 return trace.getByteOrder();
2518 } else {
2519 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2520 }
2521 }
2522 throw new ParseException("Invalid value for byte order"); //$NON-NLS-1$
2523 }
2524
2525 /**
2526 * Determines if the given value is a valid alignment value.
2527 *
2528 * @param alignment
2529 * The value to check.
2530 * @return True if it is valid.
2531 */
2532 private static boolean isValidAlignment(long alignment) {
2533 return !((alignment <= 0) || ((alignment & (alignment - 1)) != 0));
2534 }
2535
2536 /**
2537 * Gets the value of a "size" integer attribute.
2538 *
2539 * @param rightNode
2540 * A CTF_RIGHT node.
2541 * @return The "size" value.
2542 * @throws ParseException
2543 */
2544 private static long getSize(CommonTree rightNode) throws ParseException {
2545 assert (rightNode.getType() == CTFParser.CTF_RIGHT);
2546 assert (rightNode.getChildCount() > 0);
2547
2548 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2549
2550 if (isUnaryInteger(firstChild)) {
2551 if (rightNode.getChildCount() > 1) {
2552 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2553 }
2554
2555 long size = parseUnaryInteger(firstChild);
2556
2557 if (size < 1) {
2558 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2559 }
2560
2561 return size;
2562 }
2563 throw new ParseException("Invalid value for size"); //$NON-NLS-1$
2564 }
2565
2566 /**
2567 * Gets the value of a "align" integer or struct attribute.
2568 *
2569 * @param node
2570 * A CTF_RIGHT node or directly an unary integer.
2571 * @return The align value.
2572 * @throws ParseException
2573 */
2574 private static long getAlignment(CommonTree node) throws ParseException {
2575 assert (isUnaryExpression(node) || (node.getType() == CTFParser.CTF_RIGHT));
2576
2577 /*
2578 * If a CTF_RIGHT node was passed, call getAlignment with the first
2579 * child
2580 */
2581 if (node.getType() == CTFParser.CTF_RIGHT) {
2582 if (node.getChildCount() > 1) {
2583 throw new ParseException("Invalid alignment value"); //$NON-NLS-1$
2584 }
2585
2586 return getAlignment((CommonTree) node.getChild(0));
2587 } else if (isUnaryInteger(node)) {
2588 long alignment = parseUnaryInteger(node);
2589
2590 if (!isValidAlignment(alignment)) {
2591 throw new ParseException("Invalid value for alignment : " //$NON-NLS-1$
2592 + alignment);
2593 }
2594
2595 return alignment;
2596 }
2597 throw new ParseException("Invalid value for alignment"); //$NON-NLS-1$
2598 }
2599
2600 /**
2601 * Gets the value of a "base" integer attribute.
2602 *
2603 * @param rightNode
2604 * An CTF_RIGHT node.
2605 * @return The "base" value.
2606 * @throws ParseException
2607 */
2608 private static int getBase(CommonTree rightNode) throws ParseException {
2609 assert (rightNode.getType() == CTFParser.CTF_RIGHT);
2610 assert (rightNode.getChildCount() > 0);
2611
2612 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2613
2614 if (isUnaryInteger(firstChild)) {
2615 if (rightNode.getChildCount() > 1) {
2616 throw new ParseException("invalid base value"); //$NON-NLS-1$
2617 }
2618
2619 long intval = parseUnaryInteger(firstChild);
2620 if ((intval == 2) || (intval == 8) || (intval == 10)
2621 || (intval == 16)) {
2622 return (int) intval;
2623 }
2624 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2625 } else if (isUnaryString(firstChild)) {
2626 String strval = concatenateUnaryStrings(rightNode.getChildren());
2627
2628 if (strval.equals("decimal") || strval.equals("dec") //$NON-NLS-1$ //$NON-NLS-2$
2629 || strval.equals("d") || strval.equals("i") //$NON-NLS-1$ //$NON-NLS-2$
2630 || strval.equals("u")) { //$NON-NLS-1$
2631 return 10;
2632 } else if (strval.equals("hexadecimal") || strval.equals("hex") //$NON-NLS-1$ //$NON-NLS-2$
2633 || strval.equals("x") || strval.equals("X") //$NON-NLS-1$ //$NON-NLS-2$
2634 || strval.equals("p")) { //$NON-NLS-1$
2635 return 16;
2636 } else if (strval.equals("octal") || strval.equals("oct") //$NON-NLS-1$ //$NON-NLS-2$
2637 || strval.equals("o")) { //$NON-NLS-1$
2638 return 8;
2639 } else if (strval.equals("binary") || strval.equals("b")) { //$NON-NLS-1$ //$NON-NLS-2$
2640 return 2;
2641 } else {
2642 throw new ParseException("Invalid value for base"); //$NON-NLS-1$
2643 }
2644 } else {
2645 throw new ParseException("invalid value for base"); //$NON-NLS-1$
2646 }
2647 }
2648
2649 /**
2650 * Gets the value of an "encoding" integer attribute.
2651 *
2652 * @param rightNode
2653 * A CTF_RIGHT node.
2654 * @return The "encoding" value.
2655 * @throws ParseException
2656 */
2657 private static Encoding getEncoding(CommonTree rightNode)
2658 throws ParseException {
2659 assert (rightNode.getType() == CTFParser.CTF_RIGHT);
2660
2661 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2662
2663 if (isUnaryString(firstChild)) {
2664 String strval = concatenateUnaryStrings(rightNode.getChildren());
2665
2666 if (strval.equals("UTF8")) { //$NON-NLS-1$
2667 return Encoding.UTF8;
2668 } else if (strval.equals("ASCII")) { //$NON-NLS-1$
2669 return Encoding.ASCII;
2670 } else if (strval.equals("none")) { //$NON-NLS-1$
2671 return Encoding.NONE;
2672 } else {
2673 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2674 }
2675 }
2676 throw new ParseException("Invalid value for encoding"); //$NON-NLS-1$
2677 }
2678
2679 private static long getStreamID(CommonTree rightNode) throws ParseException {
2680 assert (rightNode.getType() == CTFParser.CTF_RIGHT);
2681 assert (rightNode.getChildCount() > 0);
2682
2683 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2684
2685 if (isUnaryInteger(firstChild)) {
2686 if (rightNode.getChildCount() > 1) {
2687 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2688 }
2689
2690 long intval = parseUnaryInteger(firstChild);
2691
2692 return intval;
2693 }
2694 throw new ParseException("invalid value for stream id"); //$NON-NLS-1$
2695 }
2696
2697 private static String getEventName(CommonTree rightNode)
2698 throws ParseException {
2699 assert (rightNode.getType() == CTFParser.CTF_RIGHT);
2700 assert (rightNode.getChildCount() > 0);
2701
2702 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2703
2704 if (isUnaryString(firstChild)) {
2705 String str = concatenateUnaryStrings(rightNode.getChildren());
2706
2707 return str;
2708 }
2709 throw new ParseException("invalid value for event name"); //$NON-NLS-1$
2710 }
2711
2712 private static long getEventID(CommonTree rightNode) throws ParseException {
2713 assert (rightNode.getType() == CTFParser.CTF_RIGHT);
2714 assert (rightNode.getChildCount() > 0);
2715
2716 CommonTree firstChild = (CommonTree) rightNode.getChild(0);
2717
2718 if (isUnaryInteger(firstChild)) {
2719 if (rightNode.getChildCount() > 1) {
2720 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2721 }
2722
2723 long intval = parseUnaryInteger(firstChild);
2724
2725 return intval;
2726 }
2727 throw new ParseException("invalid value for event id"); //$NON-NLS-1$
2728 }
2729
2730 /**
2731 * Concatenates a list of unary strings separated by arrows (->) or dots.
2732 *
2733 * @param strings
2734 * A list, first element being an unary string, subsequent
2735 * elements being ARROW or DOT nodes with unary strings as child.
2736 * @return The string representation of the unary string chain.
2737 */
2738 private static String concatenateUnaryStrings(List<CommonTree> strings) {
2739 assert ((strings != null) && (strings.size() > 0));
2740
2741 StringBuilder sb = new StringBuilder();
2742
2743 CommonTree first = strings.get(0);
2744 sb.append(parseUnaryString(first));
2745
2746 boolean isFirst = true;
2747
2748 for (CommonTree ref : strings) {
2749 if (isFirst) {
2750 isFirst = false;
2751 continue;
2752 }
2753
2754 assert ((ref.getType() == CTFParser.ARROW) || (ref.getType() == CTFParser.DOT));
2755 assert (ref.getChildCount() == 1);
2756
2757 CommonTree id = (CommonTree) ref.getChild(0);
2758
2759 if (ref.getType() == CTFParser.ARROW) {
2760 sb.append("->"); //$NON-NLS-1$
2761 } else { /* DOT */
2762 sb.append('.');
2763 }
2764
2765 sb.append(parseUnaryString(id));
2766 }
2767
2768 return sb.toString();
2769 }
2770
2771 /**
2772 * Throws a ParseException stating that the parent-child relation between
2773 * the given node and its parent is not valid. It means that the shape of
2774 * the AST is unexpected.
2775 *
2776 * @param child
2777 * The invalid child node.
2778 * @throws ParseException
2779 */
2780 private static void childTypeError(CommonTree child) throws ParseException {
2781 CommonTree parent = (CommonTree) child.getParent();
2782 String error = "Parent " + CTFParser.tokenNames[parent.getType()] //$NON-NLS-1$
2783 + " can't have a child of type " //$NON-NLS-1$
2784 + CTFParser.tokenNames[child.getType()] + "."; //$NON-NLS-1$
2785
2786 throw new ParseException(error);
2787 }
2788
2789 // ------------------------------------------------------------------------
2790 // Scope management
2791 // ------------------------------------------------------------------------
2792
2793 /**
2794 * Adds a new declaration scope on the top of the scope stack.
2795 */
2796 private void pushScope() {
2797 scope = new DeclarationScope(scope);
2798 }
2799
2800 /**
2801 * Removes the top declaration scope from the scope stack.
2802 */
2803 private void popScope() {
2804 assert (scope != null);
2805 scope = scope.getParentScope();
2806 }
2807
2808 /**
2809 * Returns the current declaration scope.
2810 *
2811 * @return The current declaration scope.
2812 */
2813 private DeclarationScope getCurrentScope() {
2814 assert (scope != null);
2815 return scope;
2816 }
2817
2818}
This page took 0.131889 seconds and 5 git commands to generate.