Commit | Line | Data |
---|---|---|
970ed795 | 1 | /****************************************************************************** |
d44e3c4f | 2 | * Copyright (c) 2000-2016 Ericsson Telecom AB |
970ed795 EL |
3 | * All rights reserved. This program and the accompanying materials |
4 | * are made available under the terms of the Eclipse Public License v1.0 | |
5 | * which accompanies this distribution, and is available at | |
6 | * http://www.eclipse.org/legal/epl-v10.html | |
d44e3c4f | 7 | * |
8 | * Contributors: | |
9 | * Baji, Laszlo | |
10 | * Balasko, Jeno | |
11 | * Baranyi, Botond | |
12 | * Cserveni, Akos | |
13 | * Delic, Adam | |
14 | * Feher, Csaba | |
15 | * Forstner, Matyas | |
16 | * Kovacs, Ferenc | |
17 | * Kremer, Peter | |
18 | * Raduly, Csaba | |
19 | * Szabados, Kristof | |
19700695 | 20 | * Szabo, Bence Janos |
d44e3c4f | 21 | * Szabo, Janos Zoltan – initial implementation |
22 | * Zalanyi, Balazs Andor | |
23 | * | |
970ed795 EL |
24 | ******************************************************************************/ |
25 | %option noyywrap | |
26 | %option never-interactive | |
27 | %option nounput | |
28 | %{ | |
29 | ||
30 | /* Tokenizer for TTCN-3 Core Language */ | |
31 | ||
32 | #include "../../common/dbgnew.hh" | |
33 | #include "compiler.h" | |
34 | #include "../string.hh" | |
35 | #include "../CompilerError.hh" | |
36 | #include "../Real.hh" | |
37 | #include "../Value.hh" | |
38 | #include "AST_ttcn3.hh" | |
39 | #include "Ttcnstuff.hh" // at least for PortTypeBody::PortOperationMode_t | |
40 | #include "Statement.hh" // for Statement::statementtype_t | |
41 | #include "Attributes.hh" | |
42 | ||
43 | #include <string.h> | |
44 | #include <ctype.h> | |
45 | #include <openssl/md5.h> | |
46 | ||
47 | namespace Common { | |
48 | class IndexedValue; | |
49 | class Location; | |
50 | } | |
51 | ||
52 | namespace Ttcn { | |
53 | class ParamRedirect; | |
54 | class Statement; | |
55 | class AltGuard; | |
56 | class IfClause; | |
57 | class IfClauses; | |
58 | class NamedTemplate; | |
59 | class NamedTemplates; | |
60 | class IndexedTemplate; | |
61 | class IndexedTemplates; | |
62 | class Templates; | |
63 | class CompTypeRefList; | |
64 | } | |
65 | ||
66 | using namespace Common; | |
67 | using namespace Ttcn; | |
68 | ||
69 | #include "compiler.tab.hh" | |
70 | ||
71 | #define yylval ttcn3_lval | |
72 | #define yylloc ttcn3_lloc | |
73 | ||
74 | /* global variable indicating the location of the returned token to bison */ | |
75 | extern YYLTYPE yylloc; | |
76 | ||
77 | extern bool is_erroneous_parsed; | |
78 | ||
79 | /* always points to the first character of the regexp to be recognized */ | |
80 | static int current_line, current_column; | |
81 | ||
82 | /* when reporting an error in linemarker or preprocessor | |
83 | * directive the real file name and line number is needed */ | |
84 | static const char* real_infile; | |
85 | /* real_lineno = current_line + real_lineno_offset */ | |
86 | static int real_lineno_offset; | |
87 | ||
88 | static bool dot_flag = false; | |
89 | /* type of the backup token (that was found after a dot) */ | |
90 | static int backup_token; | |
91 | /* semantic value of the backup token */ | |
92 | static YYSTYPE backup_lval; | |
93 | /* location of the backup token */ | |
94 | static YYLTYPE backup_lloc; | |
95 | ||
96 | static MD5_CTX md5_ctx; | |
97 | ||
98 | static void fill_location() | |
99 | { | |
100 | yylloc.first_line = current_line; | |
101 | yylloc.first_column = current_column; | |
102 | current_column += yyleng; | |
103 | yylloc.last_line = current_line; | |
104 | yylloc.last_column = current_column; | |
105 | } | |
106 | ||
107 | static void update_md5() | |
108 | { | |
109 | MD5_Update(&md5_ctx, yytext, yyleng); | |
110 | MD5_Update(&md5_ctx, " ", 1); | |
111 | } | |
112 | ||
113 | #define RETURN_SAVED_DOT \ | |
114 | do { \ | |
115 | yytext[0] = '\0'; \ | |
116 | yylloc.first_line = dot_line; \ | |
117 | yylloc.first_column = dot_column; \ | |
118 | yylloc.last_line = dot_line; \ | |
119 | yylloc.last_column = dot_column + 1; \ | |
120 | return '.'; \ | |
121 | } while (0) | |
122 | ||
123 | /* return macro for simple tokens without semantic value */ | |
124 | #define RETURN(ret_val) \ | |
125 | do { \ | |
126 | update_md5(); \ | |
127 | fill_location(); \ | |
128 | if (dot_flag) { \ | |
129 | backup_token = ret_val; \ | |
130 | backup_lloc = yylloc; \ | |
131 | RETURN_SAVED_DOT; \ | |
132 | } else return ret_val; \ | |
133 | } while (0) | |
134 | ||
135 | /* same as RETURN(ret_val) macro but without location update, | |
136 | * usually a return after an error */ | |
137 | #define RETURN_NOLOCUPD(ret_val) \ | |
138 | do { \ | |
139 | update_md5(); \ | |
140 | if (dot_flag) { \ | |
141 | backup_token = ret_val; \ | |
142 | backup_lloc = yylloc; \ | |
143 | RETURN_SAVED_DOT; \ | |
144 | } else return ret_val; \ | |
145 | } while (0) | |
146 | ||
147 | /* return macro for simple tokens with semantic value */ | |
148 | #define RETURN_LVAL(ret_val) \ | |
149 | do { \ | |
150 | update_md5(); \ | |
151 | fill_location(); \ | |
152 | if (dot_flag) { \ | |
153 | backup_token = ret_val; \ | |
154 | backup_lval = yylval; \ | |
155 | backup_lloc = yylloc; \ | |
156 | RETURN_SAVED_DOT; \ | |
157 | } else return ret_val; \ | |
158 | } while (0) | |
159 | ||
160 | /* return macro for special tokens that are glued together with previous dot */ | |
161 | #define RETURN_DOT(ret_val) \ | |
162 | do { \ | |
163 | update_md5(); \ | |
164 | if (dot_flag) { \ | |
165 | dot_flag = false; \ | |
166 | yylloc.first_line = dot_line; \ | |
167 | yylloc.first_column = dot_column; \ | |
168 | current_column += yyleng; \ | |
169 | yylloc.last_line = current_line; \ | |
170 | yylloc.last_column = current_column; \ | |
171 | return Dot##ret_val; \ | |
172 | } else { \ | |
173 | fill_location(); \ | |
174 | return ret_val; \ | |
175 | } \ | |
176 | } while (0) | |
177 | ||
178 | extern string *parse_charstring_value(const char *str, const Location& loc); | |
179 | ||
180 | %} | |
181 | ||
182 | NUMBER 0|([1-9][0-9]*) | |
183 | ||
184 | FLOAT ({NUMBER}\.[0-9]+)|({NUMBER}(\.[0-9]+)?[Ee][+-]?{NUMBER}) | |
185 | ||
186 | IDENTIFIER [A-Za-z][A-Za-z0-9_]* | |
187 | ||
188 | LINECOMMENT "//"[^\r\n]* | |
189 | ||
190 | WHITESPACE [ \t\v\f] | |
191 | ||
192 | NEWLINE \r|\n|\r\n | |
193 | ||
194 | LINEMARKER {NUMBER}{WHITESPACE}+\"([^\\\"\r\n]|\\[^\r\n])*\" | |
195 | ||
19700695 | 196 | UID [uU][+]?[0-9A-Fa-f]{1,8} |
197 | ||
970ed795 EL |
198 | TITAN "$#&&&(#TITANERRONEOUS$#&&^#% " |
199 | ||
200 | %x SC_blockcomment SC_cstring | |
201 | %x SC_binstring SC_binstring_bad | |
19700695 | 202 | %s SC_charkeyword |
970ed795 EL |
203 | |
204 | %% | |
205 | /* local variables of yylex() */ | |
206 | int start_line = 0, start_column = 0; /**< used by block comments and | |
207 | string literals */ | |
208 | int dot_line = 0, dot_column = 0; /**< location of the previous '.' token */ | |
209 | /* variables used when processing binary strings */ | |
210 | expstring_t binstr = NULL; /**< the string itself */ | |
211 | bool valid_bit = false, /**< binstr is valid bitstring */ | |
212 | valid_oct = false, /**< binstr is valid octetstring */ | |
213 | half_oct = false, /**< binstr is not a valid octetstr but a valid hexstr */ | |
214 | contains_match = false, /**< binstr contains matching symbol */ | |
215 | contains_ws = false; /**< binstr contains whitespace characters */ | |
216 | ||
217 | if (dot_flag) { | |
218 | if (backup_token == '.') { | |
219 | /* Two dots were found in the previous call: the first one was returned, | |
220 | * the second one is now in the backup. Let's assume that we have just | |
221 | * found the second one. */ | |
222 | dot_line = backup_lloc.first_line; | |
223 | dot_column = backup_lloc.first_column; | |
224 | } else { | |
225 | /* Return the token and its semantic value that was backed up after the | |
226 | * last token (which was a dot). */ | |
227 | dot_flag = false; | |
228 | yylval = backup_lval; | |
229 | yylloc = backup_lloc; | |
230 | return backup_token; | |
231 | } | |
232 | } | |
233 | ||
234 | ||
235 | {TITAN} { | |
236 | // hack: to avoid the erroneous parsing reporting a syntax error where it | |
237 | // also lists TTCN3ModuleKeyword as a possible nonterminal to use | |
238 | if (is_erroneous_parsed) { | |
239 | RETURN(TitanErroneousHackKeyword); | |
240 | } else { | |
241 | Location loc(infile, current_line, current_column, current_line, | |
242 | current_column + yyleng); | |
243 | loc.error("Unexpected `%s'.", yytext); | |
244 | } | |
245 | } | |
246 | ||
247 | /* Eat up comments and whitespaces */ | |
248 | ||
249 | "/*" { | |
250 | start_line = current_line; | |
251 | start_column = current_column; | |
252 | current_column += 2; | |
253 | BEGIN(SC_blockcomment); | |
254 | } | |
255 | ||
256 | <SC_blockcomment> /* -------- SC_blockcomment scope -------------- */ | |
257 | { | |
258 | ||
259 | "*/" { | |
260 | current_column += 2; | |
261 | BEGIN(INITIAL); | |
262 | } | |
263 | ||
264 | {NEWLINE} { | |
265 | current_line++; | |
266 | current_column = 0; | |
267 | } | |
268 | ||
269 | . current_column++; | |
270 | ||
271 | } /* SC_blockcomment */ | |
272 | ||
273 | {LINECOMMENT}?{NEWLINE} { | |
274 | current_line++; | |
275 | current_column = 0; | |
276 | } | |
277 | ||
278 | {LINECOMMENT} { | |
970ed795 EL |
279 | current_column += yyleng; |
280 | } | |
281 | ||
282 | {WHITESPACE}+ current_column += yyleng; | |
283 | ||
284 | /* C preprocessor line markers */ | |
285 | ||
286 | ^{WHITESPACE}*"#"({WHITESPACE}*"line")?{WHITESPACE}+{LINEMARKER}[^\r\n]*{NEWLINE} { | |
287 | bool error_flag = false; | |
288 | int real_lineno = current_line + real_lineno_offset; | |
289 | /* skipping the leading whitespaces */ | |
290 | int marker_begin = 0; | |
291 | while (yytext[marker_begin] != '#') marker_begin++; | |
292 | /* skipping the trailing whitespaces and newline */ | |
293 | int marker_end = yyleng - 1; | |
294 | while (yytext[marker_end] == '\r' || yytext[marker_end] == '\n' || | |
295 | yytext[marker_end] == ' ' || yytext[marker_end] == '\t') marker_end--; | |
296 | marker_end++; | |
297 | Location loc(real_infile, real_lineno, current_column + marker_begin, | |
298 | real_lineno, current_column + marker_end); | |
299 | Error_Context cntxt(&loc, "In preprocessor line marker"); | |
300 | /* parsing out the line number */ | |
301 | int lineno_begin = marker_begin + 1; | |
302 | while (!isdigit((unsigned char)yytext[lineno_begin])) lineno_begin++; | |
303 | int lineno_end = lineno_begin + 1; | |
304 | while (isdigit((int)yytext[lineno_end])) lineno_end++; | |
305 | errno = 0; | |
306 | int new_lineno = strtol(yytext + lineno_begin, NULL, 10); | |
307 | if (errno != 0) { | |
308 | Location lineno_loc(real_infile, real_lineno, current_column + lineno_begin, | |
309 | real_lineno, current_column + lineno_end); | |
310 | string lineno_str(lineno_end - lineno_begin, yytext + lineno_begin); | |
311 | lineno_loc.error("Line number `%s' is too large for being represented in " | |
312 | "memory: %s", lineno_str.c_str(), strerror(errno)); | |
313 | error_flag = true; | |
314 | } | |
315 | /* parsing out the file name */ | |
316 | int filename_begin = lineno_end + 1; | |
317 | while (yytext[filename_begin] != '"') filename_begin++; | |
318 | filename_begin++; | |
319 | int filename_end = filename_begin; | |
320 | while (yytext[filename_end] != '"') { | |
321 | if (yytext[filename_end] == '\\') filename_end += 2; | |
322 | else filename_end++; | |
323 | } | |
324 | Location filename_loc(real_infile, real_lineno, current_column + | |
325 | filename_begin - 1, real_lineno, current_column + filename_end + 1); | |
326 | string filename_str(filename_end - filename_begin, yytext + filename_begin); | |
327 | string *parsed_filename = parse_charstring_value(filename_str.c_str(), | |
328 | filename_loc); | |
329 | if (!parsed_filename) error_flag = true; | |
330 | /* updating the line/column counters */ | |
331 | if (error_flag) { | |
332 | /* the line marker is erroneous, use the real line numbers */ | |
333 | infile = real_infile; | |
334 | current_line = real_lineno + 1; | |
335 | real_lineno_offset = 0; | |
336 | } else { | |
337 | /* set the given line number */ | |
338 | infile = Location::add_source_file_name(*parsed_filename); | |
339 | current_line = new_lineno; | |
340 | real_lineno_offset = real_lineno + 1 - new_lineno; | |
341 | } | |
342 | current_column = 0; | |
343 | delete parsed_filename; | |
344 | } | |
345 | ||
346 | ^{WHITESPACE}*"#"[^\r\n]* { | |
347 | int real_lineno = current_line + real_lineno_offset; | |
348 | /* skip the leading and trailing whitespaces */ | |
349 | int marker_begin = 0; | |
350 | while (yytext[marker_begin] != '#') marker_begin++; | |
351 | int marker_end = yyleng - 1; | |
352 | while (yytext[marker_end] == ' ' || yytext[marker_end] == '\t') marker_end--; | |
353 | marker_end++; | |
354 | Location loc(real_infile, real_lineno, current_column + marker_begin, | |
355 | real_lineno, current_column + marker_end); | |
356 | loc.error("Invalid/unsupported preprocessor directive or line marker: `%s'", | |
357 | string(marker_end - marker_begin, yytext + marker_begin).c_str()); | |
358 | current_column += yyleng; | |
359 | } | |
360 | ||
361 | /* Keywords */ | |
362 | ||
363 | action RETURN(ActionKeyword); | |
364 | activate RETURN(ActivateKeyword); | |
365 | address RETURN(AddressKeyword); | |
366 | alive RETURN_DOT(AliveKeyword); | |
367 | all RETURN(AllKeyword); | |
368 | alt RETURN(AltKeyword); | |
369 | altstep RETURN(AltstepKeyword); | |
370 | and RETURN(AndKeyword); | |
371 | and4b RETURN(And4bKeyword); | |
372 | any RETURN(AnyKeyword); | |
373 | anytype RETURN(AnyTypeKeyword); | |
374 | apply RETURN_DOT(ApplyKeyword); | |
375 | bitstring RETURN(BitStringKeyword); | |
376 | boolean RETURN(BooleanKeyword); | |
377 | break RETURN(BreakKeyword); | |
378 | call RETURN_DOT(CallOpKeyword); | |
379 | case RETURN(CaseKeyword); | |
380 | catch RETURN_DOT(CatchOpKeyword); | |
19700695 | 381 | char { BEGIN(SC_charkeyword); RETURN(CharKeyword); } |
970ed795 EL |
382 | charstring RETURN(CharStringKeyword); |
383 | check RETURN_DOT(CheckOpKeyword); | |
384 | clear RETURN_DOT(ClearOpKeyword); | |
385 | complement RETURN(ComplementKeyword); | |
386 | component RETURN(ComponentKeyword); | |
387 | connect RETURN(ConnectKeyword); | |
388 | const RETURN(ConstKeyword); | |
389 | continue RETURN(ContinueKeyword); | |
390 | control RETURN(ControlKeyword); | |
391 | create RETURN_DOT(CreateKeyword); | |
392 | deactivate RETURN(DeactivateKeyword); | |
393 | default RETURN(DefaultKeyword); | |
394 | derefers RETURN(DerefersKeyword); | |
395 | disconnect RETURN(DisconnectKeyword); | |
396 | display RETURN(DisplayKeyword); | |
397 | do RETURN(DoKeyword); | |
398 | done RETURN_DOT(DoneKeyword); | |
399 | else RETURN(ElseKeyword); | |
400 | encode RETURN(EncodeKeyword); | |
401 | enumerated RETURN(EnumKeyword); | |
402 | error RETURN(ErrorKeyword); | |
403 | except RETURN(ExceptKeyword); | |
404 | exception RETURN(ExceptionKeyword); | |
405 | execute RETURN(ExecuteKeyword); | |
406 | extends RETURN(ExtendsKeyword); | |
407 | extension RETURN(ExtensionKeyword); | |
408 | external RETURN(ExtKeyword); | |
409 | fail RETURN(FailKeyword); | |
410 | false RETURN(FalseKeyword); | |
411 | float RETURN(FloatKeyword); | |
412 | for RETURN(ForKeyword); | |
413 | friend RETURN(FriendKeyword); | |
414 | from RETURN(FromKeyword); | |
415 | function RETURN(FunctionKeyword); | |
416 | getcall RETURN_DOT(GetCallOpKeyword); | |
417 | getreply RETURN_DOT(GetReplyOpKeyword); | |
418 | getverdict RETURN(GetVerdictKeyword); | |
419 | goto RETURN(GotoKeyword); | |
420 | group RETURN(GroupKeyword); | |
421 | halt RETURN_DOT(HaltKeyword); | |
422 | hexstring RETURN(HexStringKeyword); | |
423 | if RETURN(IfKeyword); | |
424 | ifpresent RETURN(IfPresentKeyword); | |
425 | import RETURN(ImportKeyword); | |
426 | in RETURN(InParKeyword); | |
427 | inconc RETURN(InconcKeyword); | |
428 | infinity RETURN(InfinityKeyword); | |
429 | inout RETURN(InOutParKeyword); | |
430 | integer RETURN(IntegerKeyword); | |
431 | interleave RETURN(InterleavedKeyword); | |
432 | kill RETURN_DOT(KillKeyword); | |
433 | killed RETURN_DOT(KilledKeyword); | |
434 | label RETURN(LabelKeyword); | |
435 | language RETURN(LanguageKeyword); | |
436 | length RETURN(LengthKeyword); | |
437 | log RETURN(LogKeyword); | |
438 | map RETURN(MapKeyword); | |
439 | match RETURN(MatchKeyword); | |
440 | message RETURN(MessageKeyword); | |
441 | mixed RETURN(MixedKeyword); | |
442 | mod RETURN(ModKeyword); | |
443 | modifies RETURN(ModifiesKeyword); | |
444 | module RETURN(TTCN3ModuleKeyword); | |
445 | modulepar RETURN(ModuleParKeyword); | |
446 | mtc RETURN(MTCKeyword); | |
447 | noblock RETURN(NoBlockKeyword); | |
448 | none RETURN(NoneKeyword); | |
449 | not RETURN(NotKeyword); | |
450 | not_a_number RETURN(NaNKeyword); | |
451 | not4b RETURN(Not4bKeyword); | |
452 | nowait RETURN(NowaitKeyword); | |
453 | null RETURN(NullKeyword); | |
454 | objid RETURN(ObjectIdentifierKeyword); | |
455 | octetstring RETURN(OctetStringKeyword); | |
456 | of RETURN(OfKeyword); | |
457 | omit RETURN(OmitKeyword); | |
458 | on RETURN(OnKeyword); | |
459 | optional RETURN(OptionalKeyword); | |
460 | or RETURN(OrKeyword); | |
461 | or4b RETURN(Or4bKeyword); | |
462 | out RETURN(OutParKeyword); | |
463 | override RETURN(OverrideKeyword); | |
464 | param RETURN(ParamKeyword); | |
465 | pass RETURN(PassKeyword); | |
466 | pattern RETURN(PatternKeyword); | |
467 | permutation RETURN(PermutationKeyword); | |
468 | port RETURN(PortKeyword); | |
469 | present RETURN(PresentKeyword); | |
470 | private RETURN(PrivateKeyword); | |
471 | procedure RETURN(ProcedureKeyword); | |
472 | public RETURN(PublicKeyword); | |
473 | raise RETURN_DOT(RaiseKeyword); | |
474 | read RETURN_DOT(ReadKeyword); | |
475 | receive RETURN_DOT(ReceiveOpKeyword); | |
476 | record RETURN(RecordKeyword); | |
477 | recursive RETURN(RecursiveKeyword); | |
478 | refers RETURN(RefersKeyword); | |
479 | rem RETURN(RemKeyword); | |
480 | repeat RETURN(RepeatKeyword); | |
481 | reply RETURN_DOT(ReplyKeyword); | |
482 | return RETURN(ReturnKeyword); | |
483 | running RETURN_DOT(RunningKeyword); | |
484 | runs RETURN(RunsKeyword); | |
485 | select RETURN(SelectKeyword); | |
486 | self RETURN(SelfKeyword); | |
487 | send RETURN_DOT(SendOpKeyword); | |
488 | sender RETURN(SenderKeyword); | |
489 | set RETURN(SetKeyword); | |
490 | setverdict RETURN(SetVerdictKeyword); | |
491 | signature RETURN(SignatureKeyword); | |
492 | start RETURN_DOT(StartKeyword); | |
493 | stop RETURN_DOT(StopKeyword); | |
494 | subset RETURN(SubsetKeyword); | |
495 | superset RETURN(SupersetKeyword); | |
496 | system RETURN(SystemKeyword); | |
497 | template RETURN(TemplateKeyword); | |
498 | testcase RETURN(TestcaseKeyword); | |
499 | timeout RETURN_DOT(TimeoutKeyword); | |
500 | timer RETURN(TimerKeyword); | |
501 | to RETURN(ToKeyword); | |
502 | trigger RETURN_DOT(TriggerOpKeyword); | |
503 | true RETURN(TrueKeyword); | |
504 | type RETURN(TypeDefKeyword); | |
505 | union RETURN(UnionKeyword); | |
506 | universal RETURN(UniversalKeyword); | |
507 | unmap RETURN(UnmapKeyword); | |
508 | value RETURN(ValueKeyword); | |
509 | valueof RETURN(ValueofKeyword); | |
510 | var RETURN(VarKeyword); | |
511 | variant RETURN(VariantKeyword); | |
512 | verdicttype RETURN(VerdictTypeKeyword); | |
513 | while RETURN(WhileKeyword); | |
514 | with RETURN(WithKeyword); | |
515 | xor RETURN(XorKeyword); | |
516 | xor4b RETURN(Xor4bKeyword); | |
517 | ||
feade998 | 518 | /* modifier keywords */ |
519 | ||
520 | "@nocase" RETURN(NocaseKeyword); | |
521 | "@lazy" RETURN(LazyKeyword); | |
522 | ||
970ed795 EL |
523 | /* special TITAN specific keywords */ |
524 | ||
525 | "@try" RETURN(TitanSpecificTryKeyword); | |
526 | "@catch" RETURN(TitanSpecificCatchKeyword); | |
a38c6d4c | 527 | "@profiler" RETURN(TitanSpecificProfilerKeyword); |
970ed795 | 528 | |
feade998 | 529 | |
970ed795 EL |
530 | /* Predefined function identifiers */ |
531 | ||
532 | bit2hex RETURN(bit2hexKeyword); | |
533 | bit2int RETURN(bit2intKeyword); | |
534 | bit2oct RETURN(bit2octKeyword); | |
535 | bit2str RETURN(bit2strKeyword); | |
536 | char2int RETURN(char2intKeyword); | |
537 | char2oct RETURN(char2octKeyword); | |
538 | decomp RETURN(decompKeyword); | |
539 | float2int RETURN(float2intKeyword); | |
540 | float2str RETURN(float2strKeyword); | |
541 | hex2bit RETURN(hex2bitKeyword); | |
542 | hex2int RETURN(hex2intKeyword); | |
543 | hex2oct RETURN(hex2octKeyword); | |
544 | hex2str RETURN(hex2strKeyword); | |
545 | int2bit RETURN(int2bitKeyword); | |
546 | int2char RETURN(int2charKeyword); | |
3abe9331 | 547 | int2enum RETURN(int2enumKeyword); |
970ed795 EL |
548 | int2float RETURN(int2floatKeyword); |
549 | int2hex RETURN(int2hexKeyword); | |
550 | int2oct RETURN(int2octKeyword); | |
551 | int2str RETURN(int2strKeyword); | |
552 | int2unichar RETURN(int2unicharKeyword); | |
553 | isvalue RETURN(isvalueKeyword); | |
554 | isbound RETURN(isboundKeyword); | |
555 | ischosen RETURN(ischosenKeyword); | |
556 | ispresent RETURN(ispresentKeyword); | |
557 | lengthof RETURN(lengthofKeyword); | |
558 | oct2bit RETURN(oct2bitKeyword); | |
559 | oct2char RETURN(oct2charKeyword); | |
560 | oct2hex RETURN(oct2hexKeyword); | |
561 | oct2int RETURN(oct2intKeyword); | |
562 | oct2str RETURN(oct2strKeyword); | |
563 | regexp RETURN(regexpKeyword); | |
564 | replace RETURN(replaceKeyword); | |
565 | rnd RETURN(rndKeyword); | |
566 | sizeof RETURN(sizeofKeyword); | |
567 | str2bit RETURN(str2bitKeyword); | |
568 | str2float RETURN(str2floatKeyword); | |
569 | str2hex RETURN(str2hexKeyword); | |
570 | str2int RETURN(str2intKeyword); | |
571 | str2oct RETURN(str2octKeyword); | |
572 | substr RETURN(substrKeyword); | |
573 | unichar2int RETURN(unichar2intKeyword); | |
574 | unichar2char RETURN(unichar2charKeyword); | |
575 | log2str RETURN(log2strKeyword); | |
576 | enum2int RETURN(enum2intKeyword); | |
577 | encvalue RETURN(encvalueKeyword); | |
578 | decvalue RETURN(decvalueKeyword); | |
579 | testcasename RETURN(testcasenameKeyword); | |
580 | ttcn2string RETURN(ttcn2stringKeyword); | |
581 | string2ttcn RETURN(string2ttcnKeyword); | |
582 | unichar2oct RETURN(unichar2octKeyword); | |
583 | oct2unichar RETURN(oct2unicharKeyword); | |
584 | remove_bom RETURN(remove_bomKeyWord); | |
585 | get_stringencoding RETURN(get_stringencodingKeyWord); | |
586 | encode_base64 RETURN(encode_base64KeyWord); | |
587 | decode_base64 RETURN(decode_base64KeyWord); | |
588 | ||
589 | /* Values */ | |
590 | ||
591 | {NUMBER} { | |
592 | Location loc(infile, current_line, current_column, current_line, | |
593 | current_column + yyleng); | |
594 | yylval.int_val = new int_val_t(yytext, loc); | |
595 | RETURN_LVAL(Number); | |
596 | } | |
597 | ||
598 | {FLOAT} { | |
599 | Location loc(infile, current_line, current_column, current_line, | |
600 | current_column + yyleng); | |
601 | yylval.float_val = string2Real(yytext, loc); | |
602 | RETURN_LVAL(FloatValue); | |
603 | } | |
604 | ||
605 | NULL RETURN(NullValue); | |
606 | ||
607 | "'" { | |
608 | binstr=memptystr(); | |
609 | valid_bit=true; | |
610 | valid_oct=true; | |
611 | half_oct=false; | |
612 | contains_match=false; | |
613 | contains_ws=false; | |
614 | start_line = current_line; | |
615 | start_column = current_column; | |
616 | current_column++; | |
617 | MD5_Update(&md5_ctx, yytext, yyleng); | |
618 | BEGIN(SC_binstring); | |
619 | } | |
620 | ||
621 | \" { | |
622 | yylval.str = memptystr(); | |
623 | start_line = current_line; | |
624 | start_column = current_column; | |
625 | current_column++; | |
626 | MD5_Update(&md5_ctx, yytext, yyleng); | |
627 | BEGIN(SC_cstring); | |
19700695 | 628 | } |
629 | ||
630 | <SC_charkeyword> | |
631 | { | |
632 | {UID} { | |
633 | yylval.str = mcopystrn(yytext, yyleng); | |
634 | RETURN_LVAL(Cstring); | |
635 | } | |
636 | ||
637 | [,] { RETURN(*yytext); } | |
638 | ||
639 | [)] { BEGIN(INITIAL); RETURN(*yytext); } | |
970ed795 EL |
640 | } |
641 | ||
642 | <SC_binstring> /* -------- SC_binstring scope -------------- */ | |
643 | { | |
644 | ||
645 | {WHITESPACE}+ { | |
646 | contains_ws = true; | |
647 | current_column += yyleng; | |
648 | } | |
649 | ||
650 | {WHITESPACE}*{NEWLINE} { | |
651 | contains_ws = true; | |
652 | current_line++; | |
653 | current_column = 0; | |
654 | } | |
655 | ||
656 | [01] { | |
657 | binstr = mputc(binstr, yytext[0]); | |
658 | half_oct = !half_oct; | |
659 | current_column++; | |
660 | } | |
661 | ||
662 | [2-9A-F] { | |
663 | binstr = mputc(binstr, yytext[0]); | |
664 | valid_bit = false; | |
665 | half_oct = !half_oct; | |
666 | current_column++; | |
667 | } | |
668 | ||
669 | [a-f] { | |
670 | binstr = mputc(binstr, yytext[0] - 'a' + 'A'); | |
671 | valid_bit = false; | |
672 | half_oct = !half_oct; | |
673 | current_column++; | |
674 | } | |
675 | ||
676 | "?"|"*" { | |
677 | binstr = mputc(binstr, yytext[0]); | |
678 | contains_match = true; | |
679 | if (half_oct) valid_oct = false; | |
680 | current_column++; | |
681 | } | |
682 | ||
683 | "'"[bBhHoO] { | |
684 | yylloc.first_line = start_line; | |
685 | yylloc.first_column = start_column; | |
686 | yylloc.last_line = current_line; | |
687 | yylloc.last_column = current_column + 2; | |
688 | Location loc(infile, yylloc); | |
689 | int ret_val = TOK_errval; | |
690 | switch (yytext[1]) { | |
691 | case 'b': { | |
692 | Location loc2(infile, current_line, current_column + 1, current_line, | |
693 | current_column + 2); | |
694 | loc2.warning("The last character of a bitstring literal should be " | |
695 | "`B' instead of `b'"); | |
696 | /* no break */ } | |
697 | case 'B': | |
698 | if (valid_bit) { | |
699 | if (contains_ws) loc.warning("Bitstring %s contains whitespace and/or " | |
700 | "newline character(s)", contains_match ? "match" : "value"); | |
701 | ret_val = contains_match ? BitStringMatch : Bstring; | |
702 | yylval.string_val = new string(binstr); | |
703 | } else loc.error("Bitstring value contains invalid character"); | |
704 | break; | |
705 | case 'h': { | |
706 | Location loc2(infile, current_line, current_column + 1, current_line, | |
707 | current_column + 2); | |
708 | loc2.warning("The last character of a hexstring literal should be " | |
709 | "`H' instead of `h'"); | |
710 | /* no break */ } | |
711 | case 'H': | |
712 | if (contains_ws) loc.warning("Hexstring %s contains whitespace and/or " | |
713 | "newline character(s)", contains_match ? "match" : "value"); | |
714 | ret_val = contains_match ? HexStringMatch : Hstring; | |
715 | yylval.string_val = new string(binstr); | |
716 | break; | |
717 | case 'o': { | |
718 | Location loc2(infile, current_line, current_column + 1, current_line, | |
719 | current_column + 2); | |
720 | loc2.warning("The last character of an octetstring literal should be " | |
721 | "`O' instead of `o'"); | |
722 | /* no break */ } | |
723 | case 'O': | |
724 | if (valid_oct && !half_oct) { | |
725 | if (contains_ws) loc.warning("Octetstring %s contains whitespace " | |
726 | "and/or newline character(s)", contains_match ? "match" : "value"); | |
727 | ret_val = contains_match ? OctetStringMatch : Ostring; | |
728 | yylval.string_val = new string(binstr); | |
729 | } else if (contains_match) { | |
730 | loc.error("Octetstring match contains half octet(s)"); | |
731 | } else { | |
732 | loc.error("Octetstring value contains odd number of hexadecimal " | |
733 | "digits"); | |
734 | } | |
735 | } | |
736 | MD5_Update(&md5_ctx, binstr, strlen(binstr)); | |
737 | Free(binstr); | |
738 | update_md5(); | |
739 | BEGIN(INITIAL); | |
740 | current_column += 2; | |
741 | if (dot_flag) { | |
742 | backup_token = ret_val; | |
743 | backup_lval = yylval; | |
744 | backup_lloc = yylloc; | |
745 | RETURN_SAVED_DOT; | |
746 | } else return ret_val; | |
747 | } | |
748 | ||
749 | "'" { | |
750 | yylloc.first_line = start_line; | |
751 | yylloc.first_column = start_column; | |
752 | current_column++; | |
753 | yylloc.last_line = current_line; | |
754 | yylloc.last_column = current_column; | |
755 | Location loc(infile, yylloc); | |
756 | loc.error("Invalid binary string literal. Expecting `B', `H' or `O' after " | |
757 | "the closing `''"); | |
758 | MD5_Update(&md5_ctx, binstr, strlen(binstr)); | |
759 | Free(binstr); | |
760 | BEGIN(INITIAL); | |
761 | RETURN_NOLOCUPD(TOK_errval); | |
762 | } | |
763 | ||
764 | . { | |
765 | Location loc(infile, current_line, current_column, current_line, | |
766 | current_column + 1); | |
767 | int c = (unsigned char)yytext[0]; | |
768 | loc.error("Invalid character `%c' (0x%02X) in binary string", | |
769 | isprint(c) ? c : '?', c); | |
770 | MD5_Update(&md5_ctx, binstr, strlen(binstr)); | |
771 | Free(binstr); | |
772 | MD5_Update(&md5_ctx, yytext, 1); | |
773 | current_column++; | |
774 | BEGIN(SC_binstring_bad); | |
775 | } | |
776 | ||
777 | } /* SC_binstring scope */ | |
778 | ||
779 | <SC_binstring_bad> /* -------- SC_binstring_bad scope -------------- */ | |
780 | { | |
781 | ||
782 | {WHITESPACE}+ current_column += yyleng; | |
783 | ||
784 | {WHITESPACE}*{NEWLINE} { | |
785 | current_line++; | |
786 | current_column = 0; | |
787 | } | |
788 | ||
789 | "'"[bBhHoO]? { | |
790 | current_column += yyleng; | |
791 | yylloc.first_line = start_line; | |
792 | yylloc.first_column = start_column; | |
793 | yylloc.last_line = current_line; | |
794 | yylloc.last_column = current_column; | |
795 | BEGIN(INITIAL); | |
796 | RETURN_NOLOCUPD(TOK_errval); | |
797 | } | |
798 | ||
799 | . { | |
800 | MD5_Update(&md5_ctx, yytext, yyleng); | |
801 | current_column++; | |
802 | } | |
803 | ||
804 | } /* SC_binstring_bad scope */ | |
805 | ||
806 | <SC_cstring> /* -------- SC_cstring scope -------------- */ | |
807 | { | |
808 | ||
809 | \\?{NEWLINE} { /* newline possibly preceded by backslash */ | |
810 | yylval.str = mputstr(yylval.str, yytext); | |
811 | current_line++; | |
812 | current_column = 0; | |
813 | } | |
814 | ||
815 | \"\"|\\. { /* two doublequotes or any backslash-escaped char */ | |
816 | yylval.str = mputstr(yylval.str, yytext); | |
817 | current_column += 2; | |
818 | /* Note that both get added ("external representation"). | |
819 | * parse_charstring_value() in charstring_la.l is responsible | |
820 | * for transforming the string to "internal representation" */ | |
821 | } | |
822 | ||
823 | \" { | |
824 | current_column++; | |
825 | yylloc.first_line = start_line; | |
826 | yylloc.first_column = start_column; | |
827 | yylloc.last_line = current_line; | |
828 | yylloc.last_column = current_column; | |
829 | MD5_Update(&md5_ctx, yylval.str, strlen(yylval.str)); | |
830 | update_md5(); | |
831 | BEGIN(INITIAL); | |
832 | if (dot_flag) { | |
833 | backup_token = Cstring; | |
834 | backup_lval = yylval; | |
835 | backup_lloc = yylloc; | |
836 | RETURN_SAVED_DOT; | |
837 | } else return Cstring; | |
838 | } | |
839 | ||
840 | . { | |
841 | yylval.str = mputc(yylval.str, yytext[0]); | |
842 | current_column++; | |
843 | } | |
844 | ||
845 | } /* SC_cstring scope */ | |
846 | ||
847 | /* Macros */ | |
848 | ||
849 | "%moduleId" { | |
850 | yylval.macrotype = Value::MACRO_MODULEID; | |
851 | RETURN_LVAL(MacroValue); | |
852 | } | |
853 | "%fileName" { | |
854 | yylval.macrotype = Value::MACRO_FILENAME; | |
855 | RETURN_LVAL(MacroValue); | |
856 | } | |
857 | "%lineNumber" { | |
858 | yylval.macrotype = Value::MACRO_LINENUMBER; | |
859 | RETURN_LVAL(MacroValue); | |
860 | } | |
861 | "%definitionId" { | |
862 | yylval.macrotype = Value::MACRO_DEFINITIONID; | |
863 | RETURN_LVAL(MacroValue); | |
864 | } | |
865 | "%testcaseId" { | |
866 | yylval.macrotype = Value::MACRO_TESTCASEID; | |
867 | RETURN_LVAL(MacroValue); | |
868 | } | |
869 | "%"{IDENTIFIER} { | |
870 | fill_location(); | |
871 | Location loc(infile, yylloc); | |
872 | loc.error("Invalid macro notation: `%s'", yytext); | |
873 | RETURN_NOLOCUPD(TOK_errval); | |
874 | } | |
875 | ||
876 | "__MODULE__" { | |
877 | yylval.macrotype = Value::MACRO_MODULEID; | |
878 | RETURN_LVAL(MacroValue); | |
879 | } | |
880 | "__FILE__" { | |
881 | yylval.macrotype = Value::MACRO_FILEPATH; | |
882 | RETURN_LVAL(MacroValue); | |
883 | } | |
884 | "__BFILE__" { | |
885 | yylval.macrotype = Value::MACRO_BFILENAME; | |
886 | RETURN_LVAL(MacroValue); | |
887 | } | |
888 | "__LINE__" { | |
889 | yylval.macrotype = Value::MACRO_LINENUMBER_C; | |
890 | RETURN_LVAL(MacroValue); | |
891 | } | |
892 | "__SCOPE__" { | |
893 | yylval.macrotype = Value::MACRO_SCOPE; | |
894 | RETURN_LVAL(MacroValue); | |
895 | } | |
896 | "__TESTCASE__" { | |
897 | yylval.macrotype = Value::MACRO_TESTCASEID; | |
898 | RETURN_LVAL(MacroValue); | |
899 | } | |
900 | "__"{IDENTIFIER}"__" { | |
901 | fill_location(); | |
902 | Location loc(infile, yylloc); | |
903 | loc.error("Invalid macro notation: `%s'", yytext); | |
904 | RETURN_NOLOCUPD(TOK_errval); | |
905 | } | |
906 | ||
907 | /* Multi-character operators */ | |
908 | ||
909 | ":=" RETURN(AssignmentChar); | |
910 | "\.\." RETURN(DotDot); | |
911 | "->" RETURN(PortRedirectSymbol); | |
912 | "==" RETURN(EQ); | |
913 | "!=" RETURN(NE); | |
914 | ">=" RETURN(GE); | |
915 | "<=" RETURN(LE); | |
916 | "<<" RETURN(SL); | |
917 | ">>" RETURN(SR); | |
918 | "<@" RETURN(RL); | |
919 | "@>" RETURN(_RR); | |
920 | ||
921 | "++" | | |
922 | "--" { | |
923 | fill_location(); | |
924 | Location loc(infile, yylloc); | |
925 | loc.error("Operator `%s' is reserved for future use", yytext); | |
926 | } | |
927 | ||
928 | /* Invalid operators */ | |
929 | ||
930 | "::=" { | |
931 | fill_location(); | |
932 | Location loc(infile, yylloc); | |
933 | loc.error("`::=' is not a valid assignment operator in TTCN-3. Did you mean " | |
934 | "`:='?"); | |
935 | RETURN_NOLOCUPD(AssignmentChar); | |
936 | } | |
937 | ||
938 | "=" { | |
939 | fill_location(); | |
940 | Location loc(infile, yylloc); | |
941 | loc.error("A single `=' character cannot be used in TTCN-3. Did you mean " | |
942 | "the assignment sign `:=' or the equality operator `=='?"); | |
943 | /* the former is more probable than the latter */ | |
944 | RETURN_NOLOCUPD(AssignmentChar); | |
945 | } | |
946 | ||
947 | "<>" { | |
948 | fill_location(); | |
949 | Location loc(infile, yylloc); | |
950 | loc.error("`<>' is not a valid comparison operator in TTCN-3. Did you mean " | |
951 | "`!='?"); | |
952 | RETURN_NOLOCUPD(NE); | |
953 | } | |
954 | ||
955 | /* Identifiers */ | |
956 | ||
957 | {IDENTIFIER} { | |
958 | yylval.id = new Identifier(Identifier::ID_TTCN, string(yyleng, yytext)); | |
959 | RETURN_LVAL(IDentifier); | |
960 | } | |
961 | ||
962 | /* Single character tokens (brackets, operators, etc.) */ | |
963 | ||
964 | \. { | |
965 | update_md5(); | |
966 | if (dot_flag) { | |
967 | /* store this dot in the backup */ | |
968 | backup_token = '.'; | |
969 | backup_lloc.first_line = current_line; | |
970 | backup_lloc.first_column = current_column; | |
971 | current_column++; | |
972 | backup_lloc.last_line = current_line; | |
973 | backup_lloc.last_column = current_column; | |
974 | /* return the dot that was found previously */ | |
975 | RETURN_SAVED_DOT; | |
976 | } else { | |
977 | dot_flag = true; | |
978 | dot_line = current_line; | |
979 | dot_column = current_column; | |
980 | current_column++; | |
981 | } | |
982 | } | |
983 | ||
984 | [()\[\]{}+\-\*/&:;,<>\?!] RETURN(*yytext); | |
985 | ||
986 | /* Invalid characters */ | |
987 | ||
988 | . { | |
989 | fill_location(); | |
990 | Location loc(infile, yylloc); | |
991 | int c = (unsigned char)yytext[0]; | |
992 | loc.error("Character `%c' (0x%02X) is not used in TTCN-3", | |
993 | isprint(c) ? c : '?', c); | |
994 | } | |
995 | ||
996 | /* EOF rule */ | |
997 | ||
998 | <*><<EOF>> { | |
999 | if (YY_START != INITIAL) { | |
1000 | Location loc(infile, start_line, start_column, current_line, | |
1001 | current_column); | |
1002 | switch (YY_START) { | |
1003 | case SC_blockcomment: | |
1004 | loc.error("Unterminated block comment"); | |
1005 | break; | |
1006 | case SC_binstring: | |
1007 | Free(binstr); | |
1008 | /* no break */ | |
1009 | case SC_binstring_bad: | |
1010 | loc.error("Unterminated binary string literal"); | |
1011 | break; | |
1012 | case SC_cstring: | |
1013 | Free(yylval.str); | |
1014 | loc.error("Unterminated character string literal"); | |
1015 | } | |
1016 | BEGIN(INITIAL); | |
1017 | } | |
1018 | if (dot_flag) { | |
1019 | dot_flag = false; | |
1020 | RETURN_SAVED_DOT; | |
1021 | } else { | |
1022 | yylloc.first_line = current_line; | |
1023 | yylloc.first_column = current_column; | |
1024 | yylloc.last_line = current_line; | |
1025 | yylloc.last_column = current_column + 1; | |
1026 | return EOF; | |
1027 | } | |
1028 | } | |
1029 | ||
1030 | %% | |
1031 | ||
1032 | void init_ttcn3_lex() | |
1033 | { | |
1034 | dot_flag = false; | |
1035 | current_line = 1; | |
1036 | current_column = 0; | |
1037 | real_infile = infile; | |
1038 | real_lineno_offset = 0; | |
1039 | MD5_Init(&md5_ctx); | |
1040 | } | |
1041 | ||
1042 | void init_erroneous_lex(const char* p_infile, int p_line, int p_column) | |
1043 | { | |
1044 | infile = p_infile; | |
1045 | current_line = p_line; | |
1046 | current_column = p_column; | |
1047 | real_infile = infile; | |
1048 | real_lineno_offset = 0; | |
1049 | dot_flag = false; | |
1050 | } | |
1051 | ||
1052 | void free_dot_flag_stuff() | |
1053 | { | |
1054 | if (dot_flag) { | |
1055 | dot_flag = false; | |
1056 | /* clean up the semantic value of the token that was backed up */ | |
1057 | switch (backup_token) { | |
1058 | case IDentifier: | |
1059 | delete backup_lval.id; | |
1060 | break; | |
1061 | case Bstring: | |
1062 | case Hstring: | |
1063 | case Ostring: | |
1064 | case BitStringMatch: | |
1065 | case HexStringMatch: | |
1066 | case OctetStringMatch: | |
1067 | delete backup_lval.string_val; | |
1068 | break; | |
1069 | case Cstring: | |
1070 | Free(backup_lval.str); | |
1071 | default: | |
1072 | break; | |
1073 | } | |
1074 | } | |
1075 | } | |
1076 | ||
1077 | void free_ttcn3_lex() | |
1078 | { | |
1079 | free_dot_flag_stuff(); | |
1080 | fclose(ttcn3_in); | |
1081 | ttcn3_lex_destroy(); | |
1082 | } | |
1083 | ||
1084 | /* called from ttcn3_parse_file to finalize MD5 and add it to the module */ | |
1085 | void set_md5_checksum(Ttcn::Module *m) | |
1086 | { | |
1087 | unsigned char md5_sum[MD5_DIGEST_LENGTH]; | |
1088 | MD5_Final(md5_sum, &md5_ctx); | |
1089 | m->set_checksum(sizeof(md5_sum), md5_sum); | |
1090 | } |