1 /*
2 * Copyright (c) 2009, Dmitry Peskov (dmitrypeskov@users.sourceforge.net)
3 *
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
6 *
7 * File: ttcn.c
8 * Description: Adds TTCN-3 support to Exuberant ctags
9 * Version: 0.4
10 * Author: Dmitry Peskov (dmitrypeskov@users.sourceforge.net)
11 * Based on ETSI ES 201 873-1 V3.4.1 appendix A
12 * Version history:
13 * 0.1 Initial version
14 * 0.2 Enhancement: faster binary search in keyword list
15 * Fix: skip tag generation from import definitions (import/except lists)
16 * 0.3 Fix: expression parser no longer relies on optional semicolon
17 * after a const/var/timer/modulepar definition to find where the initializer
18 * actually ends
19 * Fix: handle multiple module parameters not separated by semicolons
20 * 0.31 Fix: lexer bug, missing character after a charstring close-quote
21 * 0.4 Enhancement: tags for record/set/union members, enum values, port instances
22 * within components
23 */
24
25 /* INCLUDE FILES */
26
27 #include "general.h" /* always include first */
28 #include <stdlib.h>
29 #include <string.h> /* to declare strxxx() functions */
30 #include <ctype.h> /* to define isxxx() macros */
31 #include "parse.h" /* always include */
32 #include "read.h" /* to define file fileReadLine() */
33 #include "routines.h"
34 #include "debug.h"
35
36 /* DATA */
37
38 /* Tag kinds generated by parser */
39 typedef enum {
40 K_MODULE,
41 K_TYPE,
42 K_CONST,
43 K_TEMPLATE,
44 K_FUNCTION,
45 K_SIGNATURE,
46 K_TESTCASE,
47 K_ALTSTEP,
48 K_GROUP,
49 K_MODULEPAR,
50 K_VAR,
51 K_TIMER,
52 K_PORT,
53 K_MEMBER,
54 K_ENUM,
55 K_NONE /* No tag */
56 } ttcnKind_t;
57
58 static kindDefinition ttcnKinds [] = {
59 { true, 'M', "module", "module definition" },
60 { true, 't', "type", "type definition" },
61 { true, 'c', "const", "constant definition" },
62 { true, 'd', "template", "template definition" },
63 { true, 'f', "function", "function definition" },
64 { true, 's', "signature", "signature definition" },
65 { true, 'C', "testcase", "testcase definition" },
66 { true, 'a', "altstep", "altstep definition" },
67 { true, 'G', "group", "group definition" },
68 { true, 'P', "modulepar", "module parameter definition" },
69 { true, 'v', "var", "variable instance" },
70 { true, 'T', "timer", "timer instance" },
71 { true, 'p', "port", "port instance" },
72 { true, 'm', "member", "record/set/union member" },
73 { true, 'e', "enum", "enumeration value" }
74 };
75
76 /* TTCN token types */
77 typedef enum {
78 /* Values up to 255 are reserved for single-char tokens: '+', '-', etc. */
79 T_ID = 256, /* Identifier */
80 T_LITERAL, /* Literal: integer, real, (char|hex|octet|bit)string */
81 /* Keywords */
82 T_ACTION, T_ACTIVATE, T_ADDRESS, T_ALIVE, T_ALL, T_ALT, T_ALTSTEP, T_AND,
83 T_AND4B, T_ANY, T_ANYTYPE, T_BITSTRING, T_BOOLEAN, T_CASE, T_CALL, T_CATCH,
84 T_CHAR, T_CHARSTRING, T_CHECK, T_CLEAR, T_COMPLEMENT, T_COMPONENT,
85 T_CONNECT, T_CONST, T_CONTROL, T_CREATE, T_DEACTIVATE, T_DEFAULT,
86 T_DISCONNECT, T_DISPLAY, T_DO, T_DONE, T_ELSE, T_ENCODE, T_ENUMERATED,
87 T_ERROR, T_EXCEPT, T_EXCEPTION, T_EXECUTE, T_EXTENDS, T_EXTENSION,
88 T_EXTERNAL, T_FAIL, T_FALSE, T_FLOAT, T_FOR, T_FROM, T_FUNCTION,
89 T_GETVERDICT, T_GETCALL, T_GETREPLY, T_GOTO, T_GROUP, T_HEXSTRING, T_IF,
90 T_IFPRESENT, T_IMPORT, T_IN, T_INCONC, T_INFINITY, T_INOUT, T_INTEGER,
91 T_INTERLEAVE, T_KILL, T_KILLED, T_LABEL, T_LANGUAGE, T_LENGTH, T_LOG, T_MAP,
92 T_MATCH, T_MESSAGE, T_MIXED, T_MOD, T_MODIFIES, T_MODULE, T_MODULEPAR,
93 T_MTC, T_NOBLOCK, T_NONE, T_NOT, T_NOT4B, T_NOWAIT, T_NULL, T_OCTETSTRING,
94 T_OF, T_OMIT, T_ON, T_OPTIONAL, T_OR, T_OR4B, T_OUT, T_OVERRIDE, T_PARAM,
95 T_PASS, T_PATTERN, T_PORT, T_PROCEDURE, T_RAISE, T_READ, T_RECEIVE,
96 T_RECORD, T_RECURSIVE, T_REM, T_REPEAT, T_REPLY, T_RETURN, T_RUNNING,
97 T_RUNS, T_SELECT, T_SELF, T_SEND, T_SENDER, T_SET, T_SETVERDICT,
98 T_SIGNATURE, T_START, T_STOP, T_SUBSET, T_SUPERSET, T_SYSTEM, T_TEMPLATE,
99 T_TESTCASE, T_TIMEOUT, T_TIMER, T_TO, T_TRIGGER, T_TRUE, T_TYPE, T_UNION,
100 T_UNIVERSAL, T_UNMAP, T_VALUE, T_VALUEOF, T_VAR, T_VARIANT, T_VERDICTTYPE,
101 T_WHILE, T_WITH, T_XOR, T_XOR4B,
102 /* Double-char operators (single-char operators are returned "as is") */
103 T_OP_TO /* .. */, T_OP_EQ /* == */, T_OP_NE /* != */,
104 T_OP_LE /* <= */, T_OP_GE /* >= */, T_OP_ASS /* := */, T_OP_ARROW /* -> */,
105 T_OP_SHL /* << */, T_OP_SHR /* >> */, T_OP_ROTL /* <@ */, T_OP_ROTR /* @> */
106 } ttcnTokenType_t;
107
108 /* TTCN keywords. List MUST be sorted in alphabetic order!!! */
109 static struct s_ttcnKeyword {
110 const ttcnTokenType_t id;
111 const char * name;
112 const ttcnKind_t kind; /* Corresponding tag kind, K_NONE if none */
113 } ttcnKeywords [] = {
114 {T_ACTION, "action", K_NONE},
115 {T_ACTIVATE, "activate", K_NONE},
116 {T_ADDRESS, "address", K_NONE},
117 {T_ALIVE, "alive", K_NONE},
118 {T_ALL, "all", K_NONE},
119 {T_ALT, "alt", K_NONE},
120 {T_ALTSTEP, "altstep", K_ALTSTEP},
121 {T_AND, "and", K_NONE},
122 {T_AND4B, "and4b", K_NONE},
123 {T_ANY, "any", K_NONE},
124 {T_ANYTYPE, "anytype", K_NONE},
125 {T_BITSTRING, "bitstring", K_NONE},
126 {T_BOOLEAN, "boolean", K_NONE},
127 {T_CASE, "case", K_NONE},
128 {T_CALL, "call", K_NONE},
129 {T_CATCH, "catch", K_NONE},
130 {T_CHAR, "char", K_NONE},
131 {T_CHARSTRING, "charstring", K_NONE},
132 {T_CHECK, "check", K_NONE},
133 {T_CLEAR, "clear", K_NONE},
134 {T_COMPLEMENT, "complement", K_NONE},
135 {T_COMPONENT, "component", K_NONE},
136 {T_CONNECT, "connect", K_NONE},
137 {T_CONST, "const", K_CONST},
138 {T_CONTROL, "control", K_NONE},
139 {T_CREATE, "create", K_NONE},
140 {T_DEACTIVATE, "deactivate", K_NONE},
141 {T_DEFAULT, "default", K_NONE},
142 {T_DISCONNECT, "disconnect", K_NONE},
143 {T_DISPLAY, "display", K_NONE},
144 {T_DO, "do", K_NONE},
145 {T_DONE, "done", K_NONE},
146 {T_ELSE, "else", K_NONE},
147 {T_ENCODE, "encode", K_NONE},
148 {T_ENUMERATED, "enumerated", K_NONE},
149 {T_ERROR, "error", K_NONE},
150 {T_EXCEPT, "except", K_NONE},
151 {T_EXCEPTION, "exception", K_NONE},
152 {T_EXECUTE, "execute", K_NONE},
153 {T_EXTENDS, "extends", K_NONE},
154 {T_EXTENSION, "extension", K_NONE},
155 {T_EXTERNAL, "external", K_NONE},
156 {T_FAIL, "fail", K_NONE},
157 {T_FALSE, "false", K_NONE},
158 {T_FLOAT, "float", K_NONE},
159 {T_FOR, "for", K_NONE},
160 {T_FROM, "from", K_NONE},
161 {T_FUNCTION, "function", K_FUNCTION},
162 {T_GETVERDICT, "getverdict", K_NONE},
163 {T_GETCALL, "getcall", K_NONE},
164 {T_GETREPLY, "getreply", K_NONE},
165 {T_GOTO, "goto", K_NONE},
166 {T_GROUP, "group", K_GROUP},
167 {T_HEXSTRING, "hexstring", K_NONE},
168 {T_IF, "if", K_NONE},
169 {T_IFPRESENT, "ifpresent", K_NONE},
170 {T_IMPORT, "import", K_NONE},
171 {T_IN, "in", K_NONE},
172 {T_INCONC, "inconc", K_NONE},
173 {T_INFINITY, "infinity", K_NONE},
174 {T_INOUT, "inout", K_NONE},
175 {T_INTEGER, "integer", K_NONE},
176 {T_INTERLEAVE, "interleave", K_NONE},
177 {T_KILL, "kill", K_NONE},
178 {T_KILLED, "killed", K_NONE},
179 {T_LABEL, "label", K_NONE},
180 {T_LANGUAGE, "language", K_NONE},
181 {T_LENGTH, "length", K_NONE},
182 {T_LOG, "log", K_NONE},
183 {T_MAP, "map", K_NONE},
184 {T_MATCH, "match", K_NONE},
185 {T_MESSAGE, "message", K_NONE},
186 {T_MIXED, "mixed", K_NONE},
187 {T_MOD, "mod", K_NONE},
188 {T_MODIFIES, "modifies", K_NONE},
189 {T_MODULE, "module", K_MODULE},
190 {T_MODULEPAR, "modulepar", K_MODULEPAR},
191 {T_MTC, "mtc", K_NONE},
192 {T_NOBLOCK, "noblock", K_NONE},
193 {T_NONE, "none", K_NONE},
194 {T_NOT, "not", K_NONE},
195 {T_NOT4B, "not4b", K_NONE},
196 {T_NOWAIT, "nowait", K_NONE},
197 {T_NULL, "null", K_NONE},
198 {T_OCTETSTRING, "octetstring", K_NONE},
199 {T_OF, "of", K_NONE},
200 {T_OMIT, "omit", K_NONE},
201 {T_ON, "on", K_NONE},
202 {T_OPTIONAL, "optional", K_NONE},
203 {T_OR, "or", K_NONE},
204 {T_OR4B, "or4b", K_NONE},
205 {T_OUT, "out", K_NONE},
206 {T_OVERRIDE, "override", K_NONE},
207 {T_PARAM, "param", K_NONE},
208 {T_PASS, "pass", K_NONE},
209 {T_PATTERN, "pattern", K_NONE},
210 {T_PORT, "port", K_PORT},
211 {T_PROCEDURE, "procedure", K_NONE},
212 {T_RAISE, "raise", K_NONE},
213 {T_READ, "read", K_NONE},
214 {T_RECEIVE, "receive", K_NONE},
215 {T_RECORD, "record", K_NONE},
216 {T_RECURSIVE, "recursive", K_NONE},
217 {T_REM, "rem", K_NONE},
218 {T_REPEAT, "repeat", K_NONE},
219 {T_REPLY, "reply", K_NONE},
220 {T_RETURN, "return", K_NONE},
221 {T_RUNNING, "running", K_NONE},
222 {T_RUNS, "runs", K_NONE},
223 {T_SELECT, "select", K_NONE},
224 {T_SELF, "self", K_NONE},
225 {T_SEND, "send", K_NONE},
226 {T_SENDER, "sender", K_NONE},
227 {T_SET, "set", K_NONE},
228 {T_SETVERDICT, "setverdict", K_NONE},
229 {T_SIGNATURE, "signature", K_SIGNATURE},
230 {T_START, "start", K_NONE},
231 {T_STOP, "stop", K_NONE},
232 {T_SUBSET, "subset", K_NONE},
233 {T_SUPERSET, "superset", K_NONE},
234 {T_SYSTEM, "system", K_NONE},
235 {T_TEMPLATE, "template", K_TEMPLATE},
236 {T_TESTCASE, "testcase", K_TESTCASE},
237 {T_TIMEOUT, "timeout", K_NONE},
238 {T_TIMER, "timer", K_TIMER},
239 {T_TO, "to", K_NONE},
240 {T_TRIGGER, "trigger", K_NONE},
241 {T_TRUE, "true", K_NONE},
242 {T_TYPE, "type", K_TYPE},
243 {T_UNION, "union", K_NONE},
244 {T_UNIVERSAL, "universal", K_NONE},
245 {T_UNMAP, "unmap", K_NONE},
246 {T_VALUE, "value", K_NONE},
247 {T_VALUEOF, "valueof", K_NONE},
248 {T_VAR, "var", K_VAR},
249 {T_VARIANT, "variant", K_NONE},
250 {T_VERDICTTYPE, "verdicttype", K_NONE},
251 {T_WHILE, "while", K_NONE},
252 {T_WITH, "with", K_NONE},
253 {T_XOR, "xor", K_NONE},
254 {T_XOR4B, "xor4b", K_NONE}
255 };
256 static const int ttcnKeywordCount = ARRAY_SIZE(ttcnKeywords);
257
258 /* TTCN double-char operators */
259 static struct s_ttcnOp {
260 const ttcnTokenType_t id;
261 const char name[3];
262 } ttcnOps [] = {
263 {T_OP_TO, ".."},
264 {T_OP_EQ, "=="},
265 {T_OP_NE, "!="},
266 {T_OP_LE, "<="},
267 {T_OP_GE, ">="},
268 {T_OP_ASS, ":="},
269 {T_OP_ARROW, "->"},
270 {T_OP_SHL, "<<"},
271 {T_OP_SHR, ">>"},
272 {T_OP_ROTL, "<@"},
273 {T_OP_ROTR, "@>"}
274 };
275 static const int ttcnOpCount = ARRAY_SIZE(ttcnOps);
276
277 /* Token */
278 typedef struct s_ttcnToken {
279 ttcnTokenType_t type;
280 vString * value; /* Semantic value (T_ID and T_LITERAL only) */
281 ttcnKind_t kind; /* Corresponding tag kind (keywords only) */
282 } ttcnToken_t;
283
284 /* LEXER */
285
286 /* Functions forward declarations */
287 static void findTTCNKeyword(ttcnToken_t * pTok);
288 static void freeToken(ttcnToken_t * pTok);
289 static int getNonWhiteSpaceChar (void);
290 static ttcnToken_t * getToken (void);
291 static void ungetToken (void);
292
ttcnKeywordsCompare(const void * key,const void * member)293 static int ttcnKeywordsCompare (const void * key, const void * member)
294 {
295 return strcmp(key, ((struct s_ttcnKeyword *)member)->name);
296 }
297
298 /* Check if token is a TTCN-3 keyword or not */
findTTCNKeyword(ttcnToken_t * pTok)299 static void findTTCNKeyword(ttcnToken_t * pTok)
300 {
301 struct s_ttcnKeyword * k;
302 if (!pTok || !(pTok->value) || !(vStringValue(pTok->value)))
303 return;
304 /* Binary search */
305 k = bsearch (vStringValue (pTok->value), ttcnKeywords,
306 ttcnKeywordCount, sizeof (*ttcnKeywords),
307 ttcnKeywordsCompare);
308 if (k)
309 {
310 pTok->type = k->id;
311 pTok->kind = k->kind;
312 }
313 else
314 {
315 pTok->type = T_ID;
316 }
317 }
318
319 static ttcnToken_t * pTtcnToken = NULL;
320 static int repeatLastToken = false;
321
freeToken(ttcnToken_t * pTok)322 static void freeToken(ttcnToken_t * pTok)
323 {
324 if (pTok)
325 {
326 if (pTok->value)
327 vStringDelete(pTok->value);
328 eFree (pTok);
329 }
330 }
331
332 /* This function skips all whitespace and comments */
getNonWhiteSpaceChar(void)333 static int getNonWhiteSpaceChar (void)
334 {
335 int c, c2;
336 while (1)
337 {
338 /* Skip whitespace */
339 while (isspace(c = getcFromInputFile()) && (c != EOF));
340 /* Skip C/C++-style comment */
341 if (c=='/')
342 {
343 c2 = getcFromInputFile();
344 if (c2=='/')
345 {
346 /* Line comment */
347 while (((c = getcFromInputFile()) != EOF) && (c != '\n'));
348 continue;
349 }
350 else if (c2=='*')
351 {
352 /* Block comment */
353 while ((c = getcFromInputFile()) != EOF)
354 {
355 if (c=='*')
356 {
357 c2 = getcFromInputFile();
358 if (c2 == '/')
359 break;
360 ungetcToInputFile(c2);
361 }
362 }
363 continue;
364 }
365 else
366 {
367 /* Not a comment */
368 ungetcToInputFile(c2);
369 break;
370 }
371 }
372 break;
373 }
374 Assert (c == EOF || !isspace(c));
375 return c;
376 }
377
getToken(void)378 static ttcnToken_t * getToken (void)
379 {
380 int c, c2;
381 int i;
382 if (repeatLastToken)
383 {
384 /* If ungetToken() has been called before, return last token again */
385 repeatLastToken = false;
386 return pTtcnToken;
387 }
388 else
389 {
390 /* Clean up last token */
391 freeToken(pTtcnToken);
392 pTtcnToken = NULL;
393 }
394 /* Handle EOF and malloc errors */
395 if ((c = getNonWhiteSpaceChar()) == EOF)
396 return NULL;
397
398 pTtcnToken = xMalloc (1, ttcnToken_t);
399 pTtcnToken->type = 0;
400 pTtcnToken->value = NULL;
401 pTtcnToken->kind = K_NONE;
402
403 /* Parse tokens */
404 if (isalpha(c))
405 {
406 /* Identifier or keyword */
407 pTtcnToken->value = vStringNew();
408 do
409 {
410 vStringPut(pTtcnToken->value, c);
411 c = getcFromInputFile();
412 } while (isalnum(c) || c == '_');
413 /* Push back last char */
414 ungetcToInputFile(c);
415 /* Is it a keyword or an identifier? */
416 findTTCNKeyword(pTtcnToken);
417 }
418 else if (c == '\'')
419 {
420 /* Octetstring, bitstring, hexstring */
421 pTtcnToken->type = T_LITERAL;
422 pTtcnToken->value = vStringNew();
423 vStringPut(pTtcnToken->value, c);
424 /* Hex digits only (NB: 0/1 only in case of bitstring) */
425 while (isxdigit(c = getcFromInputFile()))
426 vStringPut(pTtcnToken->value, c);
427 /* Must be terminated with "'O", "'B" or "'H" */
428 if (c != '\'')
429 pTtcnToken->type = 0;
430 else
431 {
432 vStringPut(pTtcnToken->value, c);
433 c = getcFromInputFile();
434 if ((c != 'O') && (c != 'H') && (c != 'B'))
435 pTtcnToken->type = 0;
436 else
437 vStringPut(pTtcnToken->value, c);
438 }
439 }
440 else if (c == '"')
441 {
442 /* Charstring */
443 pTtcnToken->type = T_LITERAL;
444 pTtcnToken->value = vStringNew();
445 vStringPut(pTtcnToken->value, c);
446 while((c = getcFromInputFile()) != EOF)
447 {
448 vStringPut(pTtcnToken->value, c);
449 /* consume escaped characters */
450 if(c == '\\' && ((c2 = getcFromInputFile()) != EOF))
451 {
452 vStringPut(pTtcnToken->value, c2);
453 continue;
454 }
455 /* Double '"' represents '"' within a Charstring literal */
456 if (c == '"')
457 {
458 c2 = getcFromInputFile();
459 /* consume "" */
460 if (c2 == '"')
461 {
462 vStringPut(pTtcnToken->value, c2);
463 continue;
464 }
465 /* c is " that close string, c2 is out of string */
466 if(c2 != EOF)
467 ungetcToInputFile(c2);
468 break;
469 }
470 }
471 if (c != '"')
472 pTtcnToken->type = 0;
473 }
474 else if (isdigit(c))
475 {
476 /* Number */
477 pTtcnToken->type = T_LITERAL;
478 pTtcnToken->value = vStringNew();
479 /* Integer part */
480 do
481 vStringPut(pTtcnToken->value, c);
482 while (isdigit(c = getcFromInputFile()));
483 /* Decimal dot */
484 if (c == '.')
485 {
486 vStringPut(pTtcnToken->value, c);
487 /* Fractional part */
488 while (isdigit(c = getcFromInputFile()))
489 vStringPut(pTtcnToken->value, c);
490 }
491 /* Exponent */
492 if ((c == 'E') || (c == 'e'))
493 {
494 vStringPut(pTtcnToken->value, c);
495 /* Exponent sign */
496 if ((c = getcFromInputFile()) == '-')
497 vStringPut(pTtcnToken->value, c);
498 else
499 ungetcToInputFile(c);
500 /* Exponent integer part */
501 while (isdigit(c = getcFromInputFile()))
502 vStringPut(pTtcnToken->value, c);
503 /* Exponent decimal dot */
504 if (c == '.')
505 {
506 vStringPut(pTtcnToken->value, c);
507 /* Exponent fractional part */
508 while (isdigit(c = getcFromInputFile()))
509 vStringPut(pTtcnToken->value, c);
510 }
511 }
512 /* Push back last char */
513 ungetcToInputFile(c);
514 }
515 else
516 {
517 /* Operator, 1 or 2 chars, need to look 1 char ahead */
518 c2 = getcFromInputFile();
519 for (i = 0; i<ttcnOpCount; i++)
520 {
521 if ((c == ttcnOps[i].name[0]) && (c2 == ttcnOps[i].name[1]))
522 {
523 pTtcnToken->type = ttcnOps[i].id;
524 break;
525 }
526 }
527 if (i == ttcnOpCount)
528 {
529 /* No double-char operator found => single-char operator */
530 pTtcnToken->type = c;
531 /* Push back the second char */
532 ungetcToInputFile(c2);
533 }
534 }
535 /* Only identifier and literal tokens have a value */
536 if ((pTtcnToken->type != T_ID) && (pTtcnToken->type != T_LITERAL))
537 {
538 vStringDelete(pTtcnToken->value);
539 pTtcnToken->value = NULL;
540 }
541 return pTtcnToken;
542 }
543
ungetToken(void)544 static void ungetToken (void) { repeatLastToken = true; }
545
546 /* PARSER */
547
548 /* Functions forward declarations */
549 static ttcnToken_t * matchToken (ttcnTokenType_t toktype);
550 static int matchBrackets (const char * br);
551 static int matchExprOperator (void);
552 static int parseExprOperand (void);
553 static int parseSimpleExpression(void);
554 static int parseID (ttcnKind_t kind);
555 static int parseStringLength (void);
556 static int parseExtendedFieldReference (void);
557 static int parseArrayDef (void);
558 static int parseInitializer (void);
559 static int parseNameInitList (ttcnKind_t kind);
560 static int parseType (void);
561 static int parseSignature (void);
562 static int parseStructure (void);
563 static int parseEnumeration(void);
564 static int parseNestedTypeDef (void);
565 static int parseTypeDefBody (void);
566 static void parseTTCN (void);
567
568 /* Check if next token is of a specified type */
matchToken(ttcnTokenType_t toktype)569 static ttcnToken_t * matchToken (ttcnTokenType_t toktype)
570 {
571 ttcnToken_t * pTok = getToken();
572 if (pTok && (pTok->type == toktype))
573 return pTok;
574 ungetToken();
575 return NULL;
576 }
577
578 /* Count nested brackets, return when brackets are balanced */
matchBrackets(const char * br)579 static int matchBrackets (const char * br)
580 {
581 if (matchToken(br[0]))
582 {
583 int brcount = 1;
584 while (brcount > 0)
585 {
586 if (matchToken(br[0])) /* Open */
587 brcount++;
588 else if (matchToken(br[1])) /* Close */
589 brcount--;
590 else if (!getToken()) /* EOF */
591 return 0;
592 }
593 return 1;
594 }
595 return 0;
596 }
597 static const char BR_CUR[] = "{}";
598 static const char BR_PAR[] = "()";
599 static const char BR_SQ[] = "[]";
600 static const char BR_ANG[] = "<>";
601
602 /* List of TTCN operators.
603 A dot (.) is not a TTCN operator but it is included to simplify
604 the expression parser. Instead of treating X.Y.Z as a single primary
605 the parser treats it as an expression with 3 primaries and two dots. */
606 static const ttcnTokenType_t ttcnExprOps[] = {
607 T_OR, T_XOR, T_AND, T_NOT, T_OP_EQ, T_OP_NE, '>', '<', T_OP_GE, T_OP_LE,
608 T_OP_SHL, T_OP_SHR, T_OP_ROTL, T_OP_ROTR, T_OR4B, T_XOR4B, T_AND4B, T_NOT4B,
609 '+', '-', '&', '*', '/', T_MOD, T_REM, '.'
610 };
611 static const int ttcnExprOpCount = ARRAY_SIZE(ttcnExprOps);
612
613 /* Check if next token is an expression operator */
matchExprOperator(void)614 static int matchExprOperator (void)
615 {
616 ttcnToken_t * pTok = getToken();
617 int i;
618 if (!pTok)
619 return 0;
620 for (i = 0; i < ttcnExprOpCount; i++)
621 if (pTok->type == ttcnExprOps[i])
622 return 1;
623 /* Not found */
624 ungetToken();
625 return 0;
626 }
627
parseExprOperand(void)628 static int parseExprOperand (void)
629 {
630 ttcnToken_t * pTok;
631 if (matchBrackets(BR_PAR)) /* Nested expression in brackets */
632 return 1;
633 if (!(pTok = getToken()))
634 return 0;
635 switch (pTok->type)
636 {
637 case T_CREATE:
638 /* Create statement */
639 matchBrackets(BR_PAR);
640 matchToken(T_ALIVE);
641 return 1;
642 case T_EXECUTE:
643 case T_MATCH:
644 case T_VALUEOF:
645 case T_ACTIVATE:
646 case T_CHAR:
647 /* These tokens must be followed by something in parentheses */
648 return matchBrackets(BR_PAR);
649 case T_SELF:
650 case T_SYSTEM:
651 case T_MTC:
652 case T_RUNNING:
653 case T_ALIVE:
654 case T_GETVERDICT:
655 case T_READ:
656 case T_ANY:
657 case T_LITERAL:
658 case T_TRUE:
659 case T_FALSE:
660 case T_PASS:
661 case T_FAIL:
662 case T_INCONC:
663 case T_NONE:
664 case T_ERROR:
665 case T_NULL:
666 case T_OMIT:
667 return 1;
668 case T_ID:
669 if (!matchBrackets(BR_PAR)) /* Function call OR ... */
670 while (matchBrackets(BR_SQ)); /* ... array indexing */
671 return 1;
672 default:
673 break;
674 }
675 ungetToken();
676 return 0;
677 }
678
679 /* Too lazy to really parse expressions so the parser is rather simplistic:
680 an expression is a series of operands separated by 1 or more operators. */
parseSimpleExpression(void)681 static int parseSimpleExpression(void)
682 {
683 while (matchExprOperator()); /* Skip leading unary ops */
684 while (parseExprOperand() && matchExprOperator())
685 while (matchExprOperator());
686 return 1;
687 }
688
689 /* Check if next token is an identifier, make a tag of a specified kind */
parseID(ttcnKind_t kind)690 static int parseID (ttcnKind_t kind)
691 {
692 ttcnToken_t * pTok = matchToken(T_ID);
693 if (pTok)
694 {
695 if (kind < K_NONE)
696 makeSimpleTag(pTok->value, kind);
697 return 1;
698 }
699 return 0;
700 }
701
702 /* StringLength ::= "length" '(' ... ')' */
parseStringLength(void)703 static int parseStringLength (void)
704 {
705 return (matchToken(T_LENGTH) && matchBrackets(BR_PAR));
706 }
707
708 /* ExtendedFieldReference ::= { '.' ID | '[' ... ']' }+ */
parseExtendedFieldReference(void)709 static int parseExtendedFieldReference (void)
710 {
711 int res = 0;
712 while ((matchToken('.') && matchToken(T_ID)) || matchBrackets(BR_SQ))
713 res = 1;
714 return res;
715 }
716
717 /* ArrayDef ::= { '[' ... ']' }+ */
parseArrayDef(void)718 static int parseArrayDef (void)
719 {
720 int res = 0;
721 while (matchBrackets(BR_SQ))
722 res = 1;
723 return res;
724 }
725
726 /* Initializer ::= ":=" Expression */
parseInitializer(void)727 static int parseInitializer (void)
728 {
729 if (matchToken(T_OP_ASS))
730 {
731 /* Compound expression */
732 if (matchBrackets(BR_CUR))
733 return 1;
734 /* Simple expression */
735 return parseSimpleExpression();
736 }
737 return 0;
738 }
739
740 /* NameInitList ::= ID [ArrayDef] [Initializer]
741 { ',' ID [ArrayDef] [Initializer] }
742 Used for parsing const/modulepar/var/timer/port definitions. */
parseNameInitList(ttcnKind_t kind)743 static int parseNameInitList (ttcnKind_t kind)
744 {
745 do
746 {
747 if (!parseID(kind))
748 return 0;
749 /* NB: ArrayDef is not allowed for modulepar */
750 parseArrayDef();
751 /* NB: Initializer is mandatory for constants, not allowed for ports */
752 parseInitializer();
753 } while (matchToken(','));
754 return 1;
755 }
756
757 /* A.1.6.3 Type ::= PredefinedType | ReferencedType */
parseType(void)758 static int parseType (void)
759 {
760 ttcnToken_t * pTok = getToken();
761 if (!pTok)
762 return 0;
763 switch (pTok->type)
764 {
765 /* PredefinedType */
766 case T_BITSTRING:
767 case T_BOOLEAN:
768 case T_CHARSTRING:
769 case T_INTEGER:
770 case T_OCTETSTRING:
771 case T_HEXSTRING:
772 case T_VERDICTTYPE:
773 case T_FLOAT:
774 case T_ADDRESS:
775 case T_DEFAULT:
776 case T_ANYTYPE:
777 return 1;
778 case T_UNIVERSAL:
779 if (!matchToken(T_CHARSTRING))
780 break;
781 else
782 return 1;
783 /* ReferencedType ::= [ModuleID '.'] TypeID
784 [TypeActualParList] [ExtendedFieldReference] */
785 case T_ID:
786 /* ModuleID.TypeID */
787 if (matchToken('.') && !(matchToken(T_ID)))
788 break;
789 /* FormalTypeParList */
790 matchBrackets(BR_ANG);
791 /* TypeActualParList */
792 matchBrackets(BR_PAR);
793 /* ExtendedFieldReference */
794 parseExtendedFieldReference();
795 return 1;
796 default :
797 break;
798 }
799 ungetToken();
800 return 0;
801 }
802
803 /* A.1.6.1.5 Signature ::= "signature" [ModuleID '.'] ID */
parseSignature(void)804 static int parseSignature (void)
805 {
806 return (matchToken(T_SIGNATURE) && matchToken(T_ID) && (!matchToken('.') || matchToken(T_ID)));
807 }
808
809 /* A.1.6.1.1 Structure ::= "{" [FieldDef {"," FieldDef}] "}" */
parseStructure(void)810 static int parseStructure (void)
811 {
812 if (!matchToken('{'))
813 return 0;
814 /* Comma-separated list of fields */
815 do
816 {
817 /* StructFieldDef ::= (Type | NestedTypeDef) ID
818 [ArrayDef] [SubTypeSpec] ["optional"] */
819 if (!((parseType() || parseNestedTypeDef()) && parseID(K_MEMBER)))
820 return 0;
821 parseArrayDef();
822 /* SubTypeSpec */
823 matchBrackets(BR_PAR); /* AllowedValues */
824 parseStringLength(); /* StringLength */
825 matchToken(T_OPTIONAL); /* "optional" keyword */
826 } while (matchToken(','));
827 if (!matchToken('}'))
828 return 0;
829 return 1;
830 }
831
832 /* A.1.6.1.1 Enumeration ::= "{" [EnumDef {"," EnumDef}] "}" */
parseEnumeration(void)833 static int parseEnumeration(void)
834 {
835 if (!matchToken('{'))
836 return 0;
837 /* Comma-separated list of names and values */
838 do
839 {
840 /* EnumDef ::= ID ['(' ['-'] Value ')'] */
841 if (!parseID(K_ENUM))
842 return 0;
843 matchBrackets(BR_PAR); /* Value */
844 } while (matchToken(','));
845 if (!matchToken('}'))
846 return 0;
847 return 1;
848 }
849
850 /* NestedTypeDef ::= NestedRecordDef | NestedUnionDef | NestedSetDef |
851 NestedRecordOfDef | NestedSetOfDef | NestedEnumDef */
parseNestedTypeDef(void)852 static int parseNestedTypeDef (void)
853 {
854 ttcnToken_t * pTok = getToken();
855 if (!pTok)
856 return 0;
857 switch (pTok->type)
858 {
859 case T_RECORD:
860 case T_SET:
861 /* StringLength (optional), applies to RecordOf and SetOf */
862 parseStringLength();
863 /* RecordOf/SetOf */
864 if (matchToken(T_OF))
865 return (parseType() || parseNestedTypeDef());
866 /* This is correct, no break here! */
867 case T_UNION:
868 /* Parse Record/Set/Union structure */
869 return parseStructure();
870 case T_ENUMERATED:
871 /* Parse Enumeration values */
872 return parseEnumeration();
873 default :
874 break;
875 }
876 /* No match */
877 ungetToken();
878 return 0;
879 }
880
881 /* A.1.6.1.1 TypeDefBody ::= StructuredTypeDef | SubTypeDef */
parseTypeDefBody(void)882 static int parseTypeDefBody (void)
883 {
884 ttcnToken_t * pTok = getToken();
885 if (!pTok)
886 return 0;
887 switch (pTok->type)
888 {
889 /* StructuredTypeDef ::= RecordDef | UnionDef | SetDef |
890 RecordOfDef | SetOfDef | EnumDef | PortDef | ComponentDef */
891 case T_RECORD:
892 case T_SET:
893 /* StringLength (optional), applies to RecordOf and SetOf */
894 parseStringLength();
895 if (matchToken(T_OF)) /* RecordOf/SetOf */
896 return ((parseType() || parseNestedTypeDef()) && parseID(K_TYPE));
897 /* This is correct, no break here! */
898 case T_UNION:
899 /* Parse Record/Set/Union structure */
900 if (!(parseID(K_TYPE) || matchToken(T_ADDRESS)))
901 return 0;
902 matchBrackets(BR_PAR); /* StructDefFormalParList */
903 return parseStructure();
904 case T_ENUMERATED:
905 if (!(parseID(K_TYPE) || matchToken(T_ADDRESS)))
906 return 0;
907 return parseEnumeration();
908 case T_PORT:
909 case T_COMPONENT:
910 /* Record/Set/Union/Enum/Port/Component */
911 return parseID(K_TYPE);
912 default:
913 /* SubTypeDef */
914 ungetToken();
915 /* Stop after type name, no need to parse ArrayDef, StringLength, etc */
916 return (parseType() && parseID(K_TYPE));
917 }
918 }
919
parseTTCN(void)920 static void parseTTCN (void)
921 {
922 ttcnToken_t * pTok;
923 ttcnKind_t kind;
924 while ((pTok = getToken()))
925 {
926 kind = pTok->kind;
927 switch (pTok->type)
928 {
929 case T_MODULE: /* A.1.6.0 */
930 case T_FUNCTION: /* A.1.6.1.4 */
931 case T_SIGNATURE: /* A.1.6.1.5 */
932 case T_TESTCASE: /* A.1.6.1.6 */
933 case T_ALTSTEP: /* A.1.6.1.7 */
934 case T_GROUP: /* A.1.6.1.9 */
935 /* Def ::= Keyword ID ... */
936 parseID(kind);
937 break;
938
939 case T_VAR:
940 /* A.1.6.2.1 VarInstance ::= "var" ["template"] Type List */
941 matchToken(T_TEMPLATE);
942 case T_CONST: /* A.1.6.1.2 ConstDef ::= "const" Type List */
943 case T_PORT: /* A.1.6.1.1 PortInstance ::= "port" Type List */
944 if (!parseType())
945 break;
946 case T_TIMER: /* A.1.6.2.2 TimerInstance ::= "timer" List */
947 parseNameInitList(kind);
948 break;
949 case T_TYPE: /* A.1.6.1.1 */
950 parseTypeDefBody();
951 break;
952 case T_TEMPLATE:
953 /* A.1.6.1.3 TemplateDef ::= "template" (Type | Signature) ID ... */
954 if (parseType() || parseSignature())
955 parseID(K_TEMPLATE);
956 break;
957 case T_MODULEPAR:
958 /* A.1.6.1.12 ModuleParDef ::= "modulepar"
959 (Type ModuleParList | '{' MultitypedModuleParList '}') */
960 if (matchToken('{'))
961 {
962 /* MultitypedModuleParList ::= (Type ModuleParList [;])* */
963 while (parseType() && parseNameInitList(K_MODULEPAR))
964 /* Separating semicolons are optional */
965 while (matchToken(';'));
966 }
967 else if (parseType())
968 {
969 /* Type ModuleParList */
970 parseNameInitList(K_MODULEPAR);
971 }
972 break;
973 case T_IMPORT:
974 /* A.1.6.1.8 ImportDef = "import" "from" ModuleId ["recursive"]
975 ('{' ImportList '}') | ("all" ["except"] '{' ExceptList '}')
976 Parse import definition not to generate tags but to avoid
977 generating misleading tags from import/except lists */
978 if (!matchToken(T_FROM) || ! matchToken(T_ID))
979 break;
980 matchToken(T_RECURSIVE);
981 if (matchToken(T_ALL) && !matchToken(T_EXCEPT))
982 break;
983 /* Skip import/except list */
984 matchBrackets(BR_CUR);
985 break;
986 default :
987 break;
988 }
989 }
990 }
991
992 /* Parser definition */
TTCNParser(void)993 extern parserDefinition * TTCNParser (void)
994 {
995 static const char * const extensions [] = { "ttcn", "ttcn3", NULL };
996 parserDefinition * def = parserNew ("TTCN");
997 def->kindTable = ttcnKinds;
998 def->kindCount = ARRAY_SIZE(ttcnKinds);
999 def->extensions = extensions;
1000 def->parser = parseTTCN;
1001 return def;
1002 }
1003