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