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