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