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