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