Sync with 5.1.0
[deliverable/titan.core.git] / compiler2 / ttcn3 / pstring_la.l
1 /******************************************************************************
2 * Copyright (c) 2000-2014 Ericsson Telecom AB
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 nostack
9 %option noyylineno
10 %option noyywrap
11 %option nounput
12 %option never-interactive
13 %option prefix="pstring_yy"
14
15 %{ /* ****************** C declarations ***************** */
16
17 #include <stdio.h>
18 #include <ctype.h>
19 #include "../error.h"
20 #include "../Identifier.hh"
21 #include "../Int.hh"
22 #include "PatternString.hh"
23
24 using namespace Ttcn;
25 using namespace Common;
26
27 /** Adjust location information.
28 *
29 * \c start_index and \c end_index index into \c yytext.
30 * \c current_line and \c current_column index into the actual source line
31 * (only a part of which is in \c yytext).
32 *
33 * UPDATE_LOCATION should be called to "cover" all of yytext.
34 *
35 * @param [in] start_index index into yytext (the first character to consider)
36 * @param [in] end_index index into yytext (one-past)
37 * @param [in,out] current_line
38 * @param [in,out] current_column
39 * */
40 static void update_location(int start_index, int end_index,
41 int& current_line, int& current_column)
42 {
43 for (int i = start_index; i < yyleng && i < end_index; i++) {
44 // count CR, count LF, but count CR + LF as one
45 switch (yytext[i]) {
46 case '\r':
47 current_line++;
48 current_column = 0;
49 break;
50 case '\n':
51 if (i == 0 || yytext[i - 1] != '\r') {
52 current_line++;
53 current_column = 0;
54 }
55 break;
56 default:
57 current_column++;
58 }
59 }
60 }
61
62 // This must be side-effect-free !
63 #define UPDATE_LOCATION(start_index, end_index) \
64 update_location(start_index, end_index, current_line, current_column)
65
66 #define YY_DECL static PatternString *yylex(const char *current_file, \
67 int current_line, int current_column)
68
69 %} /* ***************** definitions ***************** */
70
71 IDENTIFIER [A-Za-z][A-Za-z0-9_]*
72 NUMBER 0|([1-9][0-9]*)
73 WS [ \t\r\n\v\f]*
74 NEWLINE \r|\n|\r\n
75
76 %% /* ***************** rules ************************* */
77
78 bool in_set = false; /* inside a [] */
79 PatternString* ps = new PatternString();
80
81 "{"{WS}{IDENTIFIER}(({WS}\.{WS}{IDENTIFIER})|({WS}\[{WS}({IDENTIFIER}|{NUMBER}){WS}\]))*{WS}"}" {
82 if (in_set) {
83 // in a set a reference (without the \N at start) is just simple text,
84 // the matched token does not contain characters that are special in a set
85 ps->addString(yytext);
86 UPDATE_LOCATION(0, yyleng);
87 } else {
88 vector<string> identifiers;
89 vector<int> beginnings;
90
91 const char * beg = yytext;
92 const char * end = 0;
93 int id_begin = 0; // the first alphanumeric character of an identifier
94 for (;;) {
95 while (isspace(*++beg) || (*beg=='[') ) ; // skip whitespace and [
96 int *current_begin = new int(beg - yytext);
97 if (!id_begin) id_begin = *current_begin;
98 end = beg;
99 while (isalnum(*++end) || *end=='_') ; // scan for the end of identifier
100
101 string* identifier = new string(end-beg, beg);
102 identifiers.add(identifier);
103 beginnings .add(current_begin);
104
105 beg = end; // end remembers the position before the whitespace
106 while (isspace(*beg) || (*beg==']') ) ++beg; // skip whitespace and ]
107 if (*beg=='}') break;
108 }
109
110 size_t num_id = identifiers.size();
111 bool error = false;
112 Ttcn::Reference *ref = 0;
113 int last = 0; // last "consumed" index into yytext
114 int old_column = 0, old_line = 0; // the beginning of the entire reference
115
116 for (size_t i = 0; i < num_id; ++i) {
117 const string & id_str = *identifiers[i];
118 const int & id_beg = *beginnings [i];
119 if (Identifier::is_reserved_word(id_str, Identifier::ID_TTCN)) {
120 UPDATE_LOCATION(last, id_beg); // consume before identifier
121 int first_line = current_line, first_column = current_column;
122 UPDATE_LOCATION(id_beg, id_beg+id_str.size()); // consume identifier
123 Location loc(current_file, first_line, first_column, current_line,
124 current_column); // location covers the identifier
125 UPDATE_LOCATION(id_beg+id_str.size(), yyleng); // consume to end
126 loc.error("Invalid reference expression: `%s' is a reserved word in TTCN-3",
127 id_str.c_str());
128 error = true;
129 break;
130 } else if (in_set) {
131 UPDATE_LOCATION(last, id_beg); // consume before identifier
132 break;
133 } else {
134 if (i==0) {
135 UPDATE_LOCATION(0, id_begin); // consume before identifier
136 old_column = current_column; old_line = current_line;
137 ref = new Ttcn::Reference(new Identifier(Identifier::ID_TTCN, id_str));
138 UPDATE_LOCATION(id_begin, last = id_begin + id_str.size());
139 } else {
140 UPDATE_LOCATION(last, id_beg);
141 Location loc(current_file, current_line, current_column, current_line,
142 current_column + id_str.size());
143 UPDATE_LOCATION(id_beg, last = id_beg + id_str.size());
144
145 int temp_i;
146 FieldOrArrayRef *fieldref = 0;
147
148 if(1 != sscanf( (id_str.c_str()), "%d", &temp_i)){
149 fieldref = new FieldOrArrayRef(new Identifier(Identifier::ID_TTCN, id_str));
150 }
151 else {
152 int_val_t* temp_intvalt = new int_val_t(temp_i);
153 Value* temp_value = new Value(Value::V_INT, temp_intvalt);
154 fieldref = new FieldOrArrayRef(temp_value);
155 }
156 if (ref) {
157 ref->set_location(loc);
158 ref->add(fieldref);
159 } else {
160 loc.error("Invalid reference expression");
161 }
162 }
163 }
164 } // next i
165
166 if (error) {
167 delete ref; // safe even if NULL
168 } else {
169 UPDATE_LOCATION(last, yyleng); // consume to the end
170 Location loc(current_file, old_line, old_column, current_line, current_column);
171 if (ref) {
172 ref->set_location(loc);
173 ps->addRef(ref);
174 } else {
175 loc.error("Invalid reference expression");
176 }
177 }
178
179 // cleanup (can't be done in the second loop because it may end early)
180 for (size_t i = 0; i < num_id; ++i) {
181 delete identifiers[i];
182 delete beginnings [i];
183 }
184 identifiers.clear();
185 beginnings .clear();
186 } //else
187 }
188
189 "{"[^}]*"}" {
190 int first_line = current_line, first_column = current_column;
191 UPDATE_LOCATION(0, yyleng);
192 Location loc(current_file, first_line, first_column, current_line,
193 current_column);
194 loc.error("Invalid reference expression: `%s'", yytext);
195 }
196
197 "\\N"{WS}"{"{WS}{IDENTIFIER}{WS}"}" {
198 int id_begin = 3;
199 while (!isalpha(yytext[id_begin])) id_begin++;
200 int id_len = 1;
201 while (isalnum(yytext[id_begin + id_len]) || yytext[id_begin + id_len] == '_')
202 id_len++;
203 string id_str(id_len, yytext + id_begin);
204 /*
205 Ttcn::Reference *ref = new Ttcn::Reference(new Identifier(
206 Identifier::ID_TTCN, id_str));
207 ref->set_location(loc);
208 ps->addRefdCharSet(ref);
209 */
210 int first_line = current_line, first_column = current_column;
211 UPDATE_LOCATION(0, yyleng);
212 Location loc(current_file, first_line, first_column, current_line,
213 current_column);
214 if (Identifier::is_reserved_word(id_str, Identifier::ID_TTCN)) {
215 loc.error("Invalid character set reference: `%s' is a reserved word in "
216 "TTCN-3", id_str.c_str());
217 } else if (in_set) {
218 loc.warning("Character set reference `\\N{%s}' is not supported, "
219 "dropped out from the set", id_str.c_str());
220 } else {
221 loc.warning("Character set reference `\\N{%s}' is not supported, "
222 "substituted with `?'", id_str.c_str());
223 ps->addChar('?');
224 }
225 }
226
227 "\\N"{WS}"{"[^}]*"}" {
228 int first_line = current_line, first_column = current_column;
229 UPDATE_LOCATION(0, yyleng);
230 Location loc(current_file, first_line, first_column, current_line,
231 current_column);
232 loc.error("Invalid character set reference: `%s'", yytext);
233 }
234
235 "\\q"{WS}"{"{WS}{NUMBER}{WS}","{WS}{NUMBER}{WS}","{WS}{NUMBER}{WS}","{WS}{NUMBER}{WS}"}" {
236 int group_begin = 3;
237 while (!isdigit(yytext[group_begin])) group_begin++;
238 UPDATE_LOCATION(0, group_begin);
239 int group_len = 1;
240 while (isdigit(yytext[group_begin + group_len])) group_len++;
241 string group_str(group_len, yytext + group_begin);
242 Location group_loc(current_file, current_line, current_column, current_line,
243 current_column + group_len);
244 Int group = string2Int(group_str, group_loc);
245 if (group < 0 || group > 127) {
246 group_loc.error("The first number of quadruple (group) must be within "
247 "the range 0 .. 127 instead of %s", Int2string(group).c_str());
248 group = group < 0 ? 0 : 127;
249 }
250 int plane_begin = group_begin + group_len + 1;
251 while (!isdigit(yytext[plane_begin])) plane_begin++;
252 UPDATE_LOCATION(group_begin, plane_begin);
253 int plane_len = 1;
254 while (isdigit(yytext[plane_begin + plane_len])) plane_len++;
255 string plane_str(plane_len, yytext + plane_begin);
256 Location plane_loc(current_file, current_line, current_column, current_line,
257 current_column + plane_len);
258 Int plane = string2Int(plane_str, plane_loc);
259 if (plane < 0 || plane > 255) {
260 plane_loc.error("The second number of quadruple (plane) must be within "
261 "the range 0 .. 255 instead of %s", Int2string(plane).c_str());
262 plane = plane < 0 ? 0 : 255;
263 }
264 int row_begin = plane_begin + plane_len + 1;
265 while (!isdigit(yytext[row_begin])) row_begin++;
266 UPDATE_LOCATION(plane_begin, row_begin);
267 int row_len = 1;
268 while (isdigit(yytext[row_begin + row_len])) row_len++;
269 string row_str(row_len, yytext + row_begin);
270 Location row_loc(current_file, current_line, current_column, current_line,
271 current_column + row_len);
272 Int row = string2Int(row_str, row_loc);
273 if (row < 0 || row > 255) {
274 row_loc.error("The third number of quadruple (row) must be within "
275 "the range 0 .. 255 instead of %s", Int2string(row).c_str());
276 row = row < 0 ? 0 : 255;
277 }
278 int cell_begin = row_begin + row_len + 1;
279 while (!isdigit(yytext[cell_begin])) cell_begin++;
280 UPDATE_LOCATION(row_begin, cell_begin);
281 int cell_len = 1;
282 while (isdigit(yytext[cell_begin + cell_len])) cell_len++;
283 string cell_str(cell_len, yytext + cell_begin);
284 Location cell_loc(current_file, current_line, current_column, current_line,
285 current_column + cell_len);
286 Int cell = string2Int(cell_str, cell_loc);
287 if (cell < 0 || cell > 255) {
288 cell_loc.error("The fourth number of quadruple (cell) must be within "
289 "the range 0 .. 255 instead of %s", Int2string(cell).c_str());
290 cell = cell < 0 ? 0 : 255;
291 }
292 bool add_quadruple = true;
293 if (group == 0 && plane == 0 && row == 0) {
294 if (isprint(cell)) {
295 switch (cell) {
296 case '-':
297 case '^':
298 if (!in_set) break;
299 case '?':
300 case '*':
301 case '\\':
302 case '[':
303 case ']':
304 case '{':
305 case '}':
306 case '"':
307 case '|':
308 case '(':
309 case ')':
310 case '#':
311 case '+':
312 ps->addChar('\\');
313 default:
314 break;
315 }
316 ps->addChar(cell);
317 add_quadruple = false;
318 } else {
319 switch (cell) {
320 case '\t':
321 ps->addString("\\t");
322 add_quadruple = false;
323 break;
324 case '\r':
325 ps->addString("\\r");
326 add_quadruple = false;
327 }
328 }
329 }
330 if (add_quadruple) {
331 ps->addString("\\q{" + Int2string(group) + "," + Int2string(plane) + "," +
332 Int2string(row) + "," + Int2string(cell) + "}");
333 }
334 UPDATE_LOCATION(cell_begin, yyleng);
335 }
336
337 "\\q"({WS}"{"[^}]*"}")? {
338 int first_line = current_line, first_column = current_column;
339 UPDATE_LOCATION(0, yyleng);
340 Location loc(current_file, first_line, first_column, current_line,
341 current_column);
342 loc.error("Invalid quadruple notation: `%s'", yytext);
343 }
344
345 "[]" {
346 if(in_set) {
347 ps->addString("\\[]");
348 in_set = false;
349 } else {
350 ps->addString("[\\]");
351 in_set = true;
352 }
353 current_column += 2;
354 }
355
356 "[^]" {
357 if(in_set) {
358 ps->addString("\\[\\^]");
359 in_set = false;
360 } else {
361 ps->addString("[^\\]");
362 in_set = true;
363 }
364 current_column += 3;
365 }
366
367 "[" {
368 if(in_set) {
369 ps->addString("\\[");
370 } else {
371 ps->addChar('[');
372 in_set = true;
373 }
374 current_column++;
375 }
376
377 "]" {
378 if (in_set) {
379 ps->addChar(']');
380 in_set = false;
381 } else {
382 Location loc(current_file, current_line, current_column, current_line,
383 current_column + 1);
384 loc.error("Unmatched `]'. Did you mean `\\]'?");
385 ps->addString("\\]");
386 }
387 current_column++;
388 }
389
390 "{"|"}" {
391 Location loc(current_file, current_line, current_column, current_line,
392 current_column + 1);
393 loc.warning("Unmatched `%c' was treated literally", yytext[0]);
394 ps->addChar('\\');
395 ps->addChar(yytext[0]);
396 current_column++;
397 }
398
399 "\\\""|"\"\"" {
400 ps->addChar('"');
401 current_column += 2;
402 }
403 /* \metachars and escaped metachars */
404 \\[dwtnrsb?*\\\[\]\-\^|()#+] {
405 ps->addString(yytext);
406 current_column += 2;
407 }
408
409 "\\"(.|{NEWLINE}) {
410 int first_line = current_line, first_column = current_column;
411 UPDATE_LOCATION(0, yyleng);
412 Location loc(current_file, first_line, first_column, current_line,
413 current_column);
414 if (isprint((unsigned char)yytext[1]))
415 loc.warning("Use of unrecognized escape sequence `\\%c' is deprecated",
416 yytext[1]);
417 else loc.warning("Use of unrecognized escape sequence is deprecated");
418 ps->addString(yytext + 1);
419 }
420
421 "#"{WS}[0-9] {
422 int first_line = current_line, first_column = current_column;
423 UPDATE_LOCATION(0, yyleng);
424 if (in_set) {
425 Location loc(current_file, first_line, first_column, current_line,
426 current_column);
427 loc.error("Number of repetitions `#n' cannot be given inside a set "
428 "expression");
429 } else if (yytext[yyleng - 1] != '1') {
430 ps->addChar('#');
431 ps->addChar(yytext[yyleng - 1]);
432 }
433 }
434
435 "#"{WS}"("{WS}{NUMBER}{WS}")" {
436 if (in_set) {
437 int first_line = current_line, first_column = current_column;
438 UPDATE_LOCATION(0, yyleng);
439 Location loc(current_file, first_line, first_column, current_line,
440 current_column);
441 loc.error("Number of repetitions `#(n)' cannot be given inside a set "
442 "expression");
443 } else {
444 int number_begin = 2;
445 while (!isdigit(yytext[number_begin])) number_begin++;
446 UPDATE_LOCATION(0, number_begin);
447 int number_len = 1;
448 while (isdigit(yytext[number_begin + number_len])) number_len++;
449 string number_str(number_len, yytext + number_begin);
450 Location number_loc(current_file, current_line, current_column,
451 current_line, current_column + number_len);
452 UPDATE_LOCATION(number_begin, yyleng);
453 Int number = string2Int(number_str, number_loc);
454 if (number < 0) {
455 number_loc.error("A non-negative integer value was expected as the "
456 "number of repetitions instead of %s", Int2string(number).c_str());
457 } else if (number != 1) ps->addString("#(" + Int2string(number) + ")");
458 }
459 }
460
461 "#"{WS}"("{WS}{NUMBER}{WS}","{WS}{NUMBER}{WS}")" {
462 int first_line = current_line, first_column = current_column;
463 if (in_set) {
464 UPDATE_LOCATION(0, yyleng);
465 Location loc(current_file, first_line, first_column, current_line,
466 current_column);
467 loc.error("Number of repetitions `#(n,m)' cannot be given inside a set "
468 "expression");
469 } else {
470 int lower_begin = 2;
471 while (!isdigit(yytext[lower_begin])) lower_begin++;
472 UPDATE_LOCATION(0, lower_begin);
473 int lower_len = 1;
474 while (isdigit(yytext[lower_begin + lower_len])) lower_len++;
475 string lower_str(lower_len, yytext + lower_begin);
476 Location lower_loc(current_file, current_line, current_column,
477 current_line, current_column + lower_len);
478 Int lower = string2Int(lower_str, lower_loc);
479 if (lower < 0) {
480 lower_loc.error("A non-negative integer value was expected as the "
481 "minimum number of repetitions instead of %s",
482 Int2string(lower).c_str());
483 lower = 0;
484 }
485 int upper_begin = lower_begin + lower_len + 1;
486 while (!isdigit(yytext[upper_begin])) upper_begin++;
487 UPDATE_LOCATION(lower_begin, upper_begin);
488 int upper_len = 1;
489 while (isdigit(yytext[upper_begin + upper_len])) upper_len++;
490 string upper_str(upper_len, yytext + upper_begin);
491 Location upper_loc(current_file, current_line, current_column,
492 current_line, current_column + upper_len);
493 UPDATE_LOCATION(upper_begin, yyleng);
494 Int upper = string2Int(upper_str, upper_loc);
495 if (upper < 0) {
496 upper_loc.error("A non-negative integer value was expected as the "
497 "maximum number of repetitions instead of %s",
498 Int2string(upper).c_str());
499 } else if (lower > upper) {
500 Location loc(current_file, first_line, first_column, current_line,
501 current_column);
502 loc.error("The lower bound is higher than the upper bound in the number "
503 "of repetitions: `#(%s,%s)'", Int2string(lower).c_str(),
504 Int2string(upper).c_str());
505 } else if (lower == upper) {
506 if (lower != 1) ps->addString("#(" + Int2string(lower) + ")");
507 } else {
508 if (lower == 0) ps->addString("#(," + Int2string(upper) + ")");
509 else ps->addString("#(" + Int2string(lower) + "," + Int2string(upper) +
510 ")");
511 }
512 }
513 }
514
515 "#"{WS}"("{WS}{NUMBER}{WS}","{WS}")" {
516 if (in_set) {
517 int first_line = current_line, first_column = current_column;
518 UPDATE_LOCATION(0, yyleng);
519 Location loc(current_file, first_line, first_column, current_line,
520 current_column);
521 loc.error("Number of repetitions `#(n,)' cannot be given inside a set "
522 "expression");
523 } else {
524 int lower_begin = 2;
525 while (!isdigit(yytext[lower_begin])) lower_begin++;
526 UPDATE_LOCATION(0, lower_begin);
527 int lower_len = 1;
528 while (isdigit(yytext[lower_begin + lower_len])) lower_len++;
529 string lower_str(lower_len, yytext + lower_begin);
530 Location lower_loc(current_file, current_line, current_column,
531 current_line, current_column + lower_len);
532 UPDATE_LOCATION(lower_begin, yyleng);
533 Int lower = string2Int(lower_str, lower_loc);
534 if (lower < 0) {
535 lower_loc.error("A non-negative integer value was expected as the "
536 "minimum number of repetitions instead of %s",
537 Int2string(lower).c_str());
538 } else if (lower == 1) ps->addChar('+');
539 else ps->addString("#(" + Int2string(lower) + ",)");
540 }
541 }
542
543 "#"{WS}"("{WS}","{WS}{NUMBER}{WS}")" {
544 if (in_set) {
545 int first_line = current_line, first_column = current_column;
546 UPDATE_LOCATION(0, yyleng);
547 Location loc(current_file, first_line, first_column, current_line,
548 current_column);
549 loc.error("Number of repetitions `#(,m)' cannot be given inside a set "
550 "expression");
551 } else {
552 int upper_begin = 3;
553 while (!isdigit(yytext[upper_begin])) upper_begin++;
554 UPDATE_LOCATION(0, upper_begin);
555 int upper_len = 1;
556 while (isdigit(yytext[upper_begin + upper_len])) upper_len++;
557 string upper_str(upper_len, yytext + upper_begin);
558 Location upper_loc(current_file, current_line, current_column,
559 current_line, current_column + upper_len);
560 UPDATE_LOCATION(upper_begin, yyleng);
561 Int upper = string2Int(upper_str, upper_loc);
562 if (upper < 0) {
563 upper_loc.error("A non-negative integer value was expected as the "
564 "maximum number of repetitions instead of %s",
565 Int2string(upper).c_str());
566 } else ps->addString("#(," + Int2string(upper) + ")");
567 }
568 }
569
570 "#"{WS}"("{WS}","{WS}")" {
571 int first_line = current_line, first_column = current_column;
572 UPDATE_LOCATION(0, yyleng);
573 if (in_set) {
574 Location loc(current_file, first_line, first_column, current_line,
575 current_column);
576 loc.error("Number of repetitions `#(,)' cannot be given inside a set "
577 "expression");
578 } else ps->addString("#(,)");
579 }
580
581 "#"{WS}"("[^)]*")" {
582 int first_line = current_line, first_column = current_column;
583 UPDATE_LOCATION(0, yyleng);
584 Location loc(current_file, first_line, first_column, current_line,
585 current_column);
586 loc.error("Invalid notation for the number of repetitions: `%s'", yytext);
587 }
588
589 "#" {
590 Location loc(current_file, current_line, current_column, current_line,
591 current_column + 1);
592 if (in_set) {
593 loc.warning("Unescaped `#' inside character set was treated literally");
594 ps->addChar('\\');
595 ps->addChar('#');
596 } else {
597 loc.error("Syntax error in the number of repetitions `#...'");
598 }
599 current_column++;
600 }
601
602 "+" {
603 if (in_set) {
604 Location loc(current_file, current_line, current_column, current_line,
605 current_column + 1);
606 loc.warning("Unescaped `+' inside character set was treated literally");
607 ps->addChar('\\');
608 }
609 ps->addChar('+');
610 current_column++;
611 }
612
613 .|{NEWLINE} {
614 ps->addString(yytext);
615 UPDATE_LOCATION(0, yyleng);
616 }
617
618 <<EOF>> {
619 if (in_set) {
620 Location loc(current_file, current_line, current_column, current_line,
621 current_column + 1);
622 loc.error("Missing `]' at the end of the string");
623 ps->addChar(']');
624 }
625 return ps;
626 }
627
628 %%
629
630 PatternString* parse_pattern(const char *str, const Location& p_loc)
631 {
632 Error_Context cntxt(&p_loc, "In character string pattern");
633 struct yy_buffer_state *flex_buffer=pstring_yy_scan_string(str);
634 if (!flex_buffer) {
635 FATAL_ERROR("parse_pattern(): flex buffer creation failed");
636 return 0;
637 }
638
639 PatternString *ps = yylex(p_loc.get_filename(), p_loc.get_first_line(),
640 p_loc.get_first_column() + 1);
641 pstring_yylex_destroy();
642
643 return ps;
644 }
This page took 0.044798 seconds and 5 git commands to generate.