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