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