Kannel: Open Source WAP and SMS gateway  svn-r5335
wslexer.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  *
59  * wslexer.c
60  *
61  * Author: Markku Rossi <mtr@iki.fi>
62  *
63  * Copyright (c) 1999-2000 WAPIT OY LTD.
64  * All rights reserved.
65  *
66  * Lexical analyzer.
67  *
68  */
69 
70 #include "wsint.h"
71 #include "wsstree.h"
72 #include "wsgram.h"
73 
74 /********************* Types and definitions ****************************/
75 
76 /* A predicate to check whether the character `ch' is a decimal
77  digit. */
78 #define WS_IS_DECIMAL_DIGIT(ch) ('0' <= (ch) && (ch) <= '9')
79 
80 /* Convert the decimal digit `ch' to an integer number. */
81 #define WS_DECIMAL_TO_INT(ch) ((ch) - '0')
82 
83 /* A predicate to check whether the character `ch' is a non-zero
84  decimal digit. */
85 #define WS_IS_NON_ZERO_DIGIT(ch) ('1' <= (ch) && (ch) <= '9')
86 
87 /* A predicate to check whether the character `ch' is an octal digit. */
88 #define WS_IS_OCTAL_DIGIT(ch) ('0' <= (ch) && (ch) <= '7')
89 
90 /* Convert the octal digit `ch' to an integer number. */
91 #define WS_OCTAL_TO_INT(ch) ((ch) - '0')
92 
93 /* A predicate to check whether the character `ch' is a hex digit. */
94 #define WS_IS_HEX_DIGIT(ch) (('0' <= (ch) && (ch) <= '9') \
95  || ('a' <= (ch) && (ch) <= 'f') \
96  || ('A' <= (ch) && (ch) <= 'F'))
97 
98 /* Convert the hex digit `ch' to an integer number. */
99 #define WS_HEX_TO_INT(ch) \
100  ('0' <= (ch) && (ch) <= '9' \
101  ? ((ch) - '0') \
102  : ('a' <= (ch) && (ch) <= 'f' \
103  ? ((ch) - 'a' + 10) \
104  : (ch) - 'A' + 10))
105 
106 /* A predicate to check whether the character `ch' is an identifier
107  starter letter. */
108 #define WS_IS_IDENTIFIER_LETTER(ch) \
109  (('a' <= (ch) && (ch) <= 'z') \
110  || ('A' <= (ch) && (ch) <= 'Z') \
111  || (ch) == '_')
112 
113 /********************* Prototypes for static functions ******************/
114 
115 int ws_yy_lex(YYSTYPE *yylval, YYLTYPE *yylloc, WsCompiler* compiler);
116 
117 /* Check whether the identifier `id', `len' is a keyword. If the
118  identifier is a keyword, the function returns WS_TRUE and sets the
119  keywords token ID to `token_return'. Otherwise the function
120  returns WS_FALSE. */
121 static WsBool lookup_keyword(char *id, size_t len, int *token_return);
122 
123 /* Convert literal integer number, stored to the buffer `buffer', into
124  a 32 bit integer number. The function will report possible integer
125  overflows to the compiler `compiler'. The function modifies the
126  contents of the buffer `buffer' but it does not free it. */
127 static WsUInt32 buffer_to_int(WsCompilerPtr compiler, WsBuffer *buffer);
128 
129 /* Read a floating point number from the decimal point to the buffer
130  `buffer'. The buffer `buffer' might already contain some leading
131  digits of the number and it always contains the decimal point. If
132  the operation is successful, the function returns WS_TRUE and it
133  returns the resulting floating point number in `result'. Otherwise
134  the function returns WS_FALSE. The buffer `buffer' must be
135  initialized before this function is called and it must be
136  uninitialized by the caller. */
137 static WsBool read_float_from_point(WsCompiler *compiler, WsBuffer *buffer,
138  WsFloat *result);
139 
140 /* Read a floating point number from the exponent part to the buffer
141  `buffer'. The buffer might already contain some leading digits and
142  fields of the floating poit number. Otherwise, the function works
143  like read_float_from_point(). */
144 static WsBool read_float_from_exp(WsCompiler *compiler, WsBuffer *buffer,
145  WsFloat *result);
146 
147 /********************* Static variables *********************************/
148 
149 /* A helper macro which expands to a strings and its length excluding
150  the trailing '\0' character. */
151 #define N(n) n, sizeof(n) - 1
152 
153 /* They keywords of the WMLScript language. This array must be sorted
154  by the keyword names. */
155 static struct
156 {
157  char *name;
158  size_t name_len;
159  int token;
160 } keywords[] = {
161  {N("access"), tACCESS},
162  {N("agent"), tAGENT},
163  {N("break"), tBREAK},
164  {N("case"), tCASE},
165  {N("catch"), tCATCH},
166  {N("class"), tCLASS},
167  {N("const"), tCONST},
168  {N("continue"), tCONTINUE},
169  {N("debugger"), tDEBUGGER},
170  {N("default"), tDEFAULT},
171  {N("delete"), tDELETE},
172  {N("div"), tIDIV},
173  {N("do"), tDO},
174  {N("domain"), tDOMAIN},
175  {N("else"), tELSE},
176  {N("enum"), tENUM},
177  {N("equiv"), tEQUIV},
178  {N("export"), tEXPORT},
179  {N("extends"), tEXTENDS},
180  {N("extern"), tEXTERN},
181  {N("false"), tFALSE},
182  {N("finally"), tFINALLY},
183  {N("for"), tFOR},
184  {N("function"), tFUNCTION},
185  {N("header"), tHEADER},
186  {N("http"), tHTTP},
187  {N("if"), tIF},
188  {N("import"), tIMPORT},
189  {N("in"), tIN},
190  {N("invalid"), tINVALID},
191  {N("isvalid"), tISVALID},
192  {N("lib"), tLIB},
193  {N("meta"), tMETA},
194  {N("name"), tNAME},
195  {N("new"), tNEW},
196  {N("null"), tNULL},
197  {N("path"), tPATH},
198  {N("private"), tPRIVATE},
199  {N("public"), tPUBLIC},
200  {N("return"), tRETURN},
201  {N("sizeof"), tSIZEOF},
202  {N("struct"), tSTRUCT},
203  {N("super"), tSUPER},
204  {N("switch"), tSWITCH},
205  {N("this"), tTHIS},
206  {N("throw"), tTHROW},
207  {N("true"), tTRUE},
208  {N("try"), tTRY},
209  {N("typeof"), tTYPEOF},
210  {N("url"), tURL},
211  {N("use"), tUSE},
212  {N("user"), tUSER},
213  {N("var"), tVAR},
214  {N("void"), tVOID},
215  {N("while"), tWHILE},
216  {N("with"), tWITH},
217 };
218 
219 static int num_keywords = sizeof(keywords) / sizeof(keywords[0]);
220 
221 /********************* Global functions *********************************/
222 
223 int ws_yy_lex(YYSTYPE *yylval, YYLTYPE *yylloc, WsCompiler* compiler)
224 {
225  WsUInt32 ch, ch2;
226  WsBuffer buffer;
227  unsigned char *p;
228  WsBool success;
229 
230  /* Just check that we get the correct amount of arguments. */
231  gw_assert(compiler->magic == COMPILER_MAGIC);
232 
233  while (ws_stream_getc(compiler->input, &ch)) {
234  /* Save the token's line number. */
235  yylloc->first_line = compiler->linenum;
236 
237  switch (ch) {
238  case '\t': /* Whitespace characters. */
239  case '\v':
240  case '\f':
241  case ' ':
242  continue;
243 
244  case '\n': /* Line terminators. */
245  case '\r':
246  if (ch == '\r' && ws_stream_getc(compiler->input, &ch2)) {
247  if (ch2 != '\n')
248  ws_stream_ungetc(compiler->input, ch2);
249  }
250  compiler->linenum++;
251  continue;
252 
253  case '!': /* !, != */
254  if (ws_stream_getc(compiler->input, &ch2)) {
255  if (ch2 == '=')
256  return tNE;
257 
258  ws_stream_ungetc(compiler->input, ch2);
259  }
260  return '!';
261 
262  case '%': /* %, %= */
263  if (ws_stream_getc(compiler->input, &ch2)) {
264  if (ch2 == '=')
265  return tREMA;
266 
267  ws_stream_ungetc(compiler->input, ch2);
268  }
269  return '%';
270 
271  case '&': /* &, &&, &= */
272  if (ws_stream_getc(compiler->input, &ch2)) {
273  if (ch2 == '&')
274  return tAND;
275  if (ch2 == '=')
276  return tANDA;
277 
278  ws_stream_ungetc(compiler->input, ch2);
279  }
280  return '&';
281 
282  case '*': /* *, *= */
283  if (ws_stream_getc(compiler->input, &ch2)) {
284  if (ch2 == '=')
285  return tMULA;
286 
287  ws_stream_ungetc(compiler->input, ch2);
288  }
289  return '*';
290 
291  case '+': /* +, ++, += */
292  if (ws_stream_getc(compiler->input, &ch2)) {
293  if (ch2 == '+')
294  return tPLUSPLUS;
295  if (ch2 == '=')
296  return tADDA;
297 
298  ws_stream_ungetc(compiler->input, ch2);
299  }
300  return '+';
301 
302  case '-': /* -, --, -= */
303  if (ws_stream_getc(compiler->input, &ch2)) {
304  if (ch2 == '-')
305  return tMINUSMINUS;
306  if (ch2 == '=')
307  return tSUBA;
308 
309  ws_stream_ungetc(compiler->input, ch2);
310  }
311  return '-';
312 
313  case '.':
314  if (ws_stream_getc(compiler->input, &ch2)) {
315  if (WS_IS_DECIMAL_DIGIT(ch2)) {
316  /* DecimalFloatLiteral. */
317  ws_buffer_init(&buffer);
318 
319  if (!ws_buffer_append_space(&buffer, &p, 2)) {
320  ws_error_memory(compiler);
321  ws_buffer_uninit(&buffer);
322  return EOF;
323  }
324 
325  p[0] = '.';
326  p[1] = (unsigned char) ch2;
327 
328  success = read_float_from_point(compiler, &buffer,
329  &yylval->vfloat);
330  ws_buffer_uninit(&buffer);
331 
332  if (!success)
333  return EOF;
334 
335  return tFLOAT;
336  }
337 
338  ws_stream_ungetc(compiler->input, ch2);
339  }
340  return '.';
341 
342  case '/': /* /, /=, block or a single line comment */
343  if (ws_stream_getc(compiler->input, &ch2)) {
344  if (ch2 == '*') {
345  /* Block comment. */
346  while (1) {
347  if (!ws_stream_getc(compiler->input, &ch)) {
348  ws_src_error(compiler, 0, "EOF in comment");
349  return EOF;
350  }
351 
352  if (ch == '\n' || ch == '\r') {
353  /* Line terminators. */
354  if (ch == '\r' && ws_stream_getc(compiler->input,
355  &ch2)) {
356  if (ch2 != '\n')
357  ws_stream_ungetc(compiler->input, ch2);
358  }
359  compiler->linenum++;
360 
361  /* Continue reading the block comment. */
362  continue;
363  }
364 
365  if (ch == '*' && ws_stream_getc(compiler->input, &ch2)) {
366  if (ch2 == '/')
367  /* The end of the comment found. */
368  break;
369  ws_stream_ungetc(compiler->input, ch2);
370  }
371  }
372  /* Continue after the comment. */
373  continue;
374  }
375  if (ch2 == '/') {
376  /* Single line comment. */
377  while (1) {
378  if (!ws_stream_getc(compiler->input, &ch))
379  /* The end of input stream reached. We accept
380  this as a valid comment terminator. */
381  break;
382 
383  if (ch == '\n' || ch == '\r') {
384  /* Line terminators. */
385  if (ch == '\r' && ws_stream_getc(compiler->input,
386  &ch2)) {
387  if (ch2 != '\n')
388  ws_stream_ungetc(compiler->input, ch2);
389  }
390  /* The end of the line (and the comment)
391  reached. */
392  compiler->linenum++;
393  break;
394  }
395  }
396  /* Continue after the comment. */
397  continue;
398  }
399  if (ch2 == '=')
400  return tDIVA;
401 
402  ws_stream_ungetc(compiler->input, ch2);
403  }
404  return '/';
405 
406  case '<': /* <, <<, <<=, <= */
407  if (ws_stream_getc(compiler->input, &ch2)) {
408  if (ch2 == '<') {
409  if (ws_stream_getc(compiler->input, &ch2)) {
410  if (ch2 == '=')
411  return tLSHIFTA;
412 
413  ws_stream_ungetc(compiler->input, ch2);
414  }
415  return tLSHIFT;
416  }
417  if (ch2 == '=')
418  return tLE;
419 
420  ws_stream_ungetc(compiler->input, ch2);
421  }
422  return '<';
423 
424  case '=': /* =, == */
425  if (ws_stream_getc(compiler->input, &ch2)) {
426  if (ch2 == '=')
427  return tEQ;
428 
429  ws_stream_ungetc(compiler->input, ch2);
430  }
431  return '=';
432 
433  case '>': /* >, >=, >>, >>=, >>>, >>>= */
434  if (ws_stream_getc(compiler->input, &ch2)) {
435  if (ch2 == '>') {
436  if (ws_stream_getc(compiler->input, &ch2)) {
437  if (ch2 == '>') {
438  if (ws_stream_getc(compiler->input, &ch2)) {
439  if (ch2 == '=')
440  return tRSZSHIFTA;
441 
442  ws_stream_ungetc(compiler->input, ch2);
443  }
444  return tRSZSHIFT;
445  }
446  if (ch2 == '=')
447  return tRSSHIFTA;
448 
449  ws_stream_ungetc(compiler->input, ch2);
450  }
451  return tRSSHIFT;
452  }
453  if (ch2 == '=')
454  return tGE;
455 
456  ws_stream_ungetc(compiler->input, ch2);
457  }
458  return '>';
459 
460  case '^': /* ^, ^= */
461  if (ws_stream_getc(compiler->input, &ch2)) {
462  if (ch2 == '=')
463  return tXORA;
464 
465  ws_stream_ungetc(compiler->input, ch2);
466  }
467  return '^';
468 
469  case '|': /* |, |=, || */
470  if (ws_stream_getc(compiler->input, &ch2)) {
471  if (ch2 == '=')
472  return tORA;
473  if (ch2 == '|')
474  return tOR;
475 
476  ws_stream_ungetc(compiler->input, ch2);
477  }
478  return '|';
479 
480  case '#': /* The simple cases. */
481  case '(':
482  case ')':
483  case ',':
484  case ':':
485  case ';':
486  case '?':
487  case '{':
488  case '}':
489  case '~':
490  return (int) ch;
491 
492  case '\'': /* String literals. */
493  case '"':
494  {
495  WsUInt32 string_end_ch = ch;
496  WsUtf8String *str = ws_utf8_alloc();
497 
498  if (str == NULL) {
499  ws_error_memory(compiler);
500  return EOF;
501  }
502 
503  while (1) {
504  if (!ws_stream_getc(compiler->input, &ch)) {
505 eof_in_string_literal:
506  ws_src_error(compiler, 0, "EOF in string literal");
507  ws_utf8_free(str);
508  return EOF;
509  }
510  if (ch == string_end_ch)
511  /* The end of string reached. */
512  break;
513 
514  if (ch == '\\') {
515  /* An escape sequence. */
516  if (!ws_stream_getc(compiler->input, &ch))
517  goto eof_in_string_literal;
518 
519  switch (ch) {
520  case '\'':
521  case '"':
522  case '\\':
523  case '/':
524  /* The character as-is. */
525  break;
526 
527  case 'b':
528  ch = '\b';
529  break;
530 
531  case 'f':
532  ch = '\f';
533  break;
534 
535  case 'n':
536  ch = '\n';
537  break;
538 
539  case 'r':
540  ch = '\r';
541  break;
542 
543  case 't':
544  ch = '\t';
545  break;
546 
547  case 'x':
548  case 'u':
549  {
550  int i, len;
551  int type = ch;
552 
553  if (ch == 'x')
554  len = 2;
555  else
556  len = 4;
557 
558  ch = 0;
559  for (i = 0; i < len; i++) {
560  if (!ws_stream_getc(compiler->input, &ch2))
561  goto eof_in_string_literal;
562  if (!WS_IS_HEX_DIGIT(ch2)) {
563  ws_src_error(compiler, 0,
564  "malformed `\\%c' escape in "
565  "string literal", (char) type);
566  ch = 0;
567  break;
568  }
569  ch *= 16;
570  ch += WS_HEX_TO_INT(ch2);
571  }
572  }
573  break;
574 
575  default:
576  if (WS_IS_OCTAL_DIGIT(ch)) {
577  int i;
578  int limit = 3;
579 
580  ch = WS_OCTAL_TO_INT(ch);
581  if (ch > 3)
582  limit = 2;
583 
584  for (i = 1; i < limit; i++) {
585  if (!ws_stream_getc(compiler->input, &ch2))
586  goto eof_in_string_literal;
587  if (!WS_IS_OCTAL_DIGIT(ch2)) {
588  ws_stream_ungetc(compiler->input, ch2);
589  break;
590  }
591 
592  ch *= 8;
593  ch += WS_OCTAL_TO_INT(ch2);
594  }
595  } else {
596  ws_src_error(compiler, 0,
597  "unknown escape sequence `\\%c' in "
598  "string literal", (char) ch);
599  ch = 0;
600  }
601  break;
602  }
603  /* FALLTHROUGH */
604  }
605 
606  if (!ws_utf8_append_char(str, ch)) {
607  ws_error_memory(compiler);
608  ws_utf8_free(str);
609  return EOF;
610  }
611  }
612 
613  if (!ws_lexer_register_utf8(compiler, str)) {
614  ws_error_memory(compiler);
615  ws_utf8_free(str);
616  return EOF;
617  }
618 
619  gw_assert(str != NULL);
620  yylval->string = str;
621 
622  return tSTRING;
623  }
624  break;
625 
626  default:
627  /* Identifiers, keywords and number constants. */
628 
629  if (WS_IS_IDENTIFIER_LETTER(ch)) {
630  WsBool got;
631  int token;
632  unsigned char *p;
633  unsigned char *np;
634  size_t len = 0;
635 
636  /* An identifier or a keyword. We start with a 256
637  * bytes long buffer but it is expanded dynamically if
638  * needed. However, 256 should be enought for most
639  * cases since the byte-code format limits the function
640  * names to 255 characters. */
641  p = ws_malloc(256);
642  if (p == NULL) {
643  ws_error_memory(compiler);
644  return EOF;
645  }
646 
647  do {
648  /* Add one extra for the possible terminator
649  character. */
650  np = ws_realloc(p, len + 2);
651  if (np == NULL) {
652  ws_error_memory(compiler);
653  ws_free(p);
654  return EOF;
655  }
656 
657  p = np;
658 
659  /* This is ok since the only valid identifier names
660  * can be written in 7 bit ASCII. */
661  p[len++] = (unsigned char) ch;
662  } while ((got = ws_stream_getc(compiler->input, &ch))
664  || WS_IS_DECIMAL_DIGIT(ch)));
665 
666  if (got)
667  /* Put back the terminator character. */
668  ws_stream_ungetc(compiler->input, ch);
669 
670  /* Is it a keyword? */
671  if (lookup_keyword((char *) p, len, &token)) {
672  /* Yes it is... */
673  ws_free(p);
674 
675  /* ...except one case: `div='. */
676  if (token == tIDIV) {
677  if (ws_stream_getc(compiler->input, &ch)) {
678  if (ch == '=')
679  return tIDIVA;
680 
681  ws_stream_ungetc(compiler->input, ch);
682  }
683  }
684 
685  /* Return the token value. */
686  return token;
687  }
688 
689  /* It is a normal identifier. Let's pad the name with a
690  null-character. We have already allocated space for
691  it. */
692  p[len] = '\0';
693 
694  if (!ws_lexer_register_block(compiler, p)) {
695  ws_error_memory(compiler);
696  ws_free(p);
697  return EOF;
698  }
699 
700  gw_assert(p != NULL);
701  yylval->identifier = (char *) p;
702 
703  return tIDENTIFIER;
704  }
705 
706  if (WS_IS_NON_ZERO_DIGIT(ch)) {
707  /* A decimal integer literal or a decimal float
708  literal. */
709 
710  ws_buffer_init(&buffer);
711  if (!ws_buffer_append_space(&buffer, &p, 1)) {
712 number_error_memory:
713  ws_error_memory(compiler);
714  ws_buffer_uninit(&buffer);
715  return EOF;
716  }
717  p[0] = ch;
718 
719  while (ws_stream_getc(compiler->input, &ch)) {
720  if (WS_IS_DECIMAL_DIGIT(ch)) {
721  if (!ws_buffer_append_space(&buffer, &p, 1))
722  goto number_error_memory;
723  p[0] = ch;
724  } else if (ch == '.' || ch == 'e' || ch == 'E') {
725  /* DecimalFloatLiteral. */
726  if (ch == '.') {
727  if (!ws_buffer_append_space(&buffer, &p, 1))
728  goto number_error_memory;
729  p[0] = '.';
730 
731  success = read_float_from_point(compiler, &buffer,
732  &yylval->vfloat);
733  } else {
734  ws_stream_ungetc(compiler->input, ch);
735 
736  success = read_float_from_exp(compiler, &buffer,
737  &yylval->vfloat);
738  }
739  ws_buffer_uninit(&buffer);
740 
741  if (!success)
742  return EOF;
743 
744  return tFLOAT;
745  } else {
746  ws_stream_ungetc(compiler->input, ch);
747  break;
748  }
749  }
750 
751  /* Now the buffer contains an integer number as a
752  string. Let's convert it to an integer number. */
753  yylval->integer = buffer_to_int(compiler, &buffer);
754  ws_buffer_uninit(&buffer);
755 
756  /* Read a DecimalIntegerLiteral. */
757  return tINTEGER;
758  }
759 
760  if (ch == '0') {
761  /* The integer constant 0, an octal number or a
762  HexIntegerLiteral. */
763  if (ws_stream_getc(compiler->input, &ch2)) {
764  if (ch2 == 'x' || ch2 == 'X') {
765  /* HexIntegerLiteral. */
766 
767  ws_buffer_init(&buffer);
768  if (!ws_buffer_append_space(&buffer, &p, 2))
769  goto number_error_memory;
770 
771  p[0] = '0';
772  p[1] = 'x';
773 
774  while (ws_stream_getc(compiler->input, &ch)) {
775  if (WS_IS_HEX_DIGIT(ch)) {
776  if (!ws_buffer_append_space(&buffer, &p, 1))
777  goto number_error_memory;
778  p[0] = ch;
779  } else {
780  ws_stream_ungetc(compiler->input, ch);
781  break;
782  }
783  }
784 
785  if (ws_buffer_len(&buffer) == 2) {
786  ws_buffer_uninit(&buffer);
787  ws_src_error(compiler, 0,
788  "numeric constant with no digits");
789  yylval->integer = 0;
790  return tINTEGER;
791  }
792 
793  /* Now the buffer contains an integer number as
794  * a string. Let's convert it to an integer
795  * number. */
796  yylval->integer = buffer_to_int(compiler, &buffer);
797  ws_buffer_uninit(&buffer);
798 
799  /* Read a HexIntegerLiteral. */
800  return tINTEGER;
801  }
802  if (WS_IS_OCTAL_DIGIT(ch2)) {
803  /* OctalIntegerLiteral. */
804 
805  ws_buffer_init(&buffer);
806  if (!ws_buffer_append_space(&buffer, &p, 2))
807  goto number_error_memory;
808 
809  p[0] = '0';
810  p[1] = ch2;
811 
812  while (ws_stream_getc(compiler->input, &ch)) {
813  if (WS_IS_OCTAL_DIGIT(ch)) {
814  if (!ws_buffer_append_space(&buffer, &p, 1))
815  goto number_error_memory;
816  p[0] = ch;
817  } else {
818  ws_stream_ungetc(compiler->input, ch);
819  break;
820  }
821  }
822 
823  /* Convert the buffer into an intger number. */
824  yylval->integer = buffer_to_int(compiler, &buffer);
825  ws_buffer_uninit(&buffer);
826 
827  /* Read an OctalIntegerLiteral. */
828  return tINTEGER;
829  }
830  if (ch2 == '.' || ch2 == 'e' || ch2 == 'E') {
831  /* DecimalFloatLiteral. */
832  ws_buffer_init(&buffer);
833 
834  if (ch2 == '.') {
835  if (!ws_buffer_append_space(&buffer, &p, 1))
836  goto number_error_memory;
837  p[0] = '.';
838 
839  success = read_float_from_point(compiler, &buffer,
840  &yylval->vfloat);
841  } else {
842  ws_stream_ungetc(compiler->input, ch);
843 
844  success = read_float_from_exp(compiler, &buffer,
845  &yylval->vfloat);
846  }
847  ws_buffer_uninit(&buffer);
848 
849  if (!success)
850  return EOF;
851 
852  return tFLOAT;
853  }
854 
855  ws_stream_ungetc(compiler->input, ch2);
856  }
857 
858  /* Integer literal 0. */
859  yylval->integer = 0;
860  return tINTEGER;
861  }
862 
863  /* Garbage found from the input stream. */
864  ws_src_error(compiler, 0,
865  "garbage found from the input stream: character=0x%x",
866  ch);
867  return EOF;
868  break;
869  }
870  }
871 
872  return EOF;
873 }
874 
875 /********************* Static functions *********************************/
876 
877 static WsBool lookup_keyword(char *id, size_t len, int *token_return)
878 {
879  int left = 0, center, right = num_keywords;
880 
881  while (left < right) {
882  size_t l;
883  int result;
884 
885  center = left + (right - left) / 2;
886 
887  l = keywords[center].name_len;
888  if (len < l)
889  l = len;
890 
891  result = memcmp(id, keywords[center].name, l);
892  if (result < 0 || (result == 0 && len < keywords[center].name_len))
893  /* The possible match is smaller. */
894  right = center;
895  else if (result > 0 || (result == 0 && len > keywords[center].name_len))
896  /* The possible match is bigger. */
897  left = center + 1;
898  else {
899  /* Found a match. */
900  *token_return = keywords[center].token;
901  return WS_TRUE;
902  }
903  }
904 
905  /* No match. */
906  return WS_FALSE;
907 }
908 
909 
910 static WsUInt32 buffer_to_int(WsCompilerPtr compiler, WsBuffer *buffer)
911 {
912  unsigned char *p;
913  unsigned long value;
914 
915  /* Terminate the string. */
916  if (!ws_buffer_append_space(buffer, &p, 1)) {
917  ws_error_memory(compiler);
918  return 0;
919  }
920  p[0] = '\0';
921 
922  /* Convert the buffer into an integer number. The base is taken
923  from the bufer. */
924  errno = 0;
925  value = strtoul((char *) ws_buffer_ptr(buffer), NULL, 0);
926 
927  /* Check for overflow. We accept WS_INT32_MAX + 1 because we might
928  * be parsing the numeric part of '-2147483648'. */
929  if (errno == ERANGE || value > (WsUInt32) WS_INT32_MAX + 1)
930  ws_src_error(compiler, 0, "integer literal too large");
931 
932  /* All done. */
933  return (WsUInt32) value;
934 }
935 
936 
938  WsFloat *result)
939 {
940  WsUInt32 ch;
941  unsigned char *p;
942 
943  while (ws_stream_getc(compiler->input, &ch)) {
944  if (WS_IS_DECIMAL_DIGIT(ch)) {
945  if (!ws_buffer_append_space(buffer, &p, 1)) {
946  ws_error_memory(compiler);
947  return WS_FALSE;
948  }
949  p[0] = (unsigned char) ch;
950  } else {
951  ws_stream_ungetc(compiler->input, ch);
952  break;
953  }
954  }
955 
956  return read_float_from_exp(compiler, buffer, result);
957 }
958 
959 
960 static WsBool read_float_from_exp(WsCompiler *compiler, WsBuffer *buffer,
961  WsFloat *result)
962 {
963  WsUInt32 ch;
964  unsigned char *p;
965  int sign = '+';
966  unsigned char buf[4];
967 
968  /* Do we have an exponent part. */
969  if (!ws_stream_getc(compiler->input, &ch))
970  goto done;
971  if (ch != 'e' && ch != 'E') {
972  /* No exponent part. */
973  ws_stream_ungetc(compiler->input, ch);
974  goto done;
975  }
976 
977  /* Sign. */
978  if (!ws_stream_getc(compiler->input, &ch)) {
979  /* This is an error. */
980  ws_src_error(compiler, 0, "truncated float literal");
981  return WS_FALSE;
982  }
983  if (ch == '-')
984  sign = '-';
985  else if (ch == '+')
986  sign = '+';
987  else
988  ws_stream_ungetc(compiler->input, ch);
989 
990  /* DecimalDigits. */
991  if (!ws_stream_getc(compiler->input, &ch)) {
992  ws_src_error(compiler, 0, "truncated float literal");
993  return WS_FALSE;
994  }
995  if (!WS_IS_DECIMAL_DIGIT(ch)) {
996  ws_src_error(compiler, 0, "no decimal digits in exponent part");
997  return WS_FALSE;
998  }
999 
1000  /* Append exponent part read so far. */
1001  if (!ws_buffer_append_space(buffer, &p, 2)) {
1002  ws_error_memory(compiler);
1003  return WS_FALSE;
1004  }
1005  p[0] = 'e';
1006  p[1] = sign;
1007 
1008  /* Read decimal digits. */
1009  while (WS_IS_DECIMAL_DIGIT(ch)) {
1010  if (!ws_buffer_append_space(buffer, &p, 1)) {
1011  ws_error_memory(compiler);
1012  return WS_FALSE;
1013  }
1014  p[0] = (unsigned char) ch;
1015 
1016  if (!ws_stream_getc(compiler->input, &ch))
1017  /* EOF. This is ok. */
1018  goto done;
1019  }
1020  /* Unget the extra character. */
1021  ws_stream_ungetc(compiler->input, ch);
1022 
1023  /* FALLTHROUGH */
1024 
1025 done:
1026 
1027  if (!ws_buffer_append_space(buffer, &p, 1)) {
1028  ws_error_memory(compiler);
1029  return WS_FALSE;
1030  }
1031  p[0] = 0;
1032 
1033  /* Now the buffer contains a valid floating point number. */
1034  *result = (WsFloat) strtod((char *) ws_buffer_ptr(buffer), NULL);
1035 
1036  /* Check that the generated floating point number fits to
1037  `float32'. */
1038  if (*result == HUGE_VAL || *result == -HUGE_VAL
1039  || ws_ieee754_encode_single(*result, buf) != WS_IEEE754_OK)
1040  ws_src_error(compiler, 0, "floating point literal too large");
1041 
1042  return WS_TRUE;
1043 }
WsUtf8String * string
Definition: wsgram.c:304
#define tDELETE
Definition: wsgram.c:243
#define tTHROW
Definition: wsgram.c:269
#define tVAR
Definition: wsgram.c:240
#define tIMPORT
Definition: wsgram.c:262
size_t name_len
Definition: wslexer.c:158
#define tSWITCH
Definition: wsgram.c:268
#define tNULL
Definition: wsgram.c:247
Definition: wsint.h:131
static WsBool lookup_keyword(char *id, size_t len, int *token_return)
Definition: wslexer.c:877
#define tFOR
Definition: wsgram.c:227
#define tFALSE
Definition: wsgram.c:212
#define tEXTENDS
Definition: wsgram.c:260
#define tPLUSPLUS
Definition: wsgram.c:277
gw_assert(wtls_machine->packet_to_send !=NULL)
unsigned long WsUInt32
Definition: wsint.h:122
#define tDIVA
Definition: wsgram.c:285
void ws_free(void *ptr)
Definition: wsalloc.c:139
#define tRSSHIFT
Definition: wsgram.c:280
#define tLIB
Definition: wsgram.c:245
#define tRSZSHIFTA
Definition: wsgram.c:292
#define tUSE
Definition: wsgram.c:238
double WsFloat
Definition: wsint.h:126
#define tPUBLIC
Definition: wsgram.c:264
#define tAGENT
Definition: wsgram.c:218
WsUInt32 magic
Definition: wsint.h:190
WsStream * input
Definition: wsint.h:196
#define WS_IS_HEX_DIGIT(ch)
Definition: wslexer.c:94
#define tGE
Definition: wsgram.c:273
#define tAND
Definition: wsgram.c:275
#define tDO
Definition: wsgram.c:257
#define tACCESS
Definition: wsgram.c:217
int type
Definition: smsc_cimd2.c:215
WsBool ws_stream_getc(WsStream *stream, WsUInt32 *ch_return)
Definition: wsstream.c:74
#define tCATCH
Definition: wsgram.c:252
#define WS_INT32_MAX
Definition: wsint.h:109
size_t ws_buffer_len(WsBuffer *buffer)
Definition: wsbuffer.c:139
void * ws_realloc(void *ptr, size_t size)
Definition: wsalloc.c:89
#define tTYPEOF
Definition: wsgram.c:237
#define tDOMAIN
Definition: wsgram.c:223
WsIeee754Result ws_ieee754_encode_single(double value, unsigned char *buf)
Definition: wsieee754.c:94
#define tPATH
Definition: wsgram.c:235
#define tWITH
Definition: wsgram.c:250
void ws_utf8_free(WsUtf8String *string)
Definition: wsutf8.c:188
static WsBool read_float_from_point(WsCompiler *compiler, WsBuffer *buffer, WsFloat *result)
Definition: wslexer.c:937
#define tRSSHIFTA
Definition: wsgram.c:291
#define tIN
Definition: wsgram.c:244
#define tREMA
Definition: wsgram.c:289
#define tEQUIV
Definition: wsgram.c:225
WsUInt32 linenum
Definition: wsint.h:201
static int num_keywords
Definition: wslexer.c:219
static struct @117 keywords[]
#define tLSHIFTA
Definition: wsgram.c:290
#define tOR
Definition: wsgram.c:276
WsBool ws_lexer_register_utf8(WsCompiler *compiler, WsUtf8String *string)
Definition: ws.c:267
int ws_utf8_append_char(WsUtf8String *string, unsigned long ch)
Definition: wsutf8.c:198
#define N(n)
Definition: wslexer.c:151
WsUtf8String * ws_utf8_alloc()
Definition: wsutf8.c:182
#define tIDIVA
Definition: wsgram.c:222
#define tIF
Definition: wsgram.c:231
int token
Definition: wslexer.c:159
void ws_stream_ungetc(WsStream *stream, WsUInt32 ch)
Definition: wsstream.c:101
#define tNAME
Definition: wsgram.c:234
#define tMETA
Definition: wsgram.c:233
#define tWHILE
Definition: wsgram.c:241
#define tISVALID
Definition: wsgram.c:232
#define tFLOAT
Definition: wsgram.c:214
#define tNEW
Definition: wsgram.c:246
WsUInt32 integer
Definition: wsgram.c:301
#define WS_OCTAL_TO_INT(ch)
Definition: wslexer.c:91
#define tTRUE
Definition: wsgram.c:211
#define tEXTERN
Definition: wsgram.c:226
#define WS_IS_DECIMAL_DIGIT(ch)
Definition: wslexer.c:78
#define tPRIVATE
Definition: wsgram.c:263
void ws_buffer_init(WsBuffer *buffer)
Definition: wsbuffer.c:74
int first_line
Definition: wsgram.c:329
#define tURL
Definition: wsgram.c:242
#define tBREAK
Definition: wsgram.c:219
#define tEQ
Definition: wsgram.c:271
#define tMULA
Definition: wsgram.c:284
#define WS_IS_OCTAL_DIGIT(ch)
Definition: wslexer.c:88
#define tNE
Definition: wsgram.c:274
#define tSUBA
Definition: wsgram.c:283
#define tINVALID
Definition: wsgram.c:210
#define WS_HEX_TO_INT(ch)
Definition: wslexer.c:99
#define tHEADER
Definition: wsgram.c:229
#define tRETURN
Definition: wsgram.c:236
#define tELSE
Definition: wsgram.c:224
void ws_buffer_uninit(WsBuffer *buffer)
Definition: wsbuffer.c:81
#define tCONST
Definition: wsgram.c:254
#define tENUM
Definition: wsgram.c:258
#define tLE
Definition: wsgram.c:272
#define tTRY
Definition: wsgram.c:270
#define tMINUSMINUS
Definition: wsgram.c:278
WsBool
Definition: wsint.h:128
WsBool ws_lexer_register_block(WsCompiler *compiler, void *ptr)
Definition: ws.c:248
#define tSIZEOF
Definition: wsgram.c:265
#define tFUNCTION
Definition: wsgram.c:228
WsFloat vfloat
Definition: wsgram.c:302
#define tINTEGER
Definition: wsgram.c:213
WsBool ws_buffer_append_space(WsBuffer *buffer, unsigned char **p, size_t size)
Definition: wsbuffer.c:115
#define tUSER
Definition: wsgram.c:239
#define tCLASS
Definition: wsgram.c:253
#define tXORA
Definition: wsgram.c:288
#define tORA
Definition: wsgram.c:287
#define tLSHIFT
Definition: wsgram.c:279
#define tHTTP
Definition: wsgram.c:230
#define tFINALLY
Definition: wsgram.c:261
#define tIDENTIFIER
Definition: wsgram.c:216
char * identifier
Definition: wsgram.c:303
static WsBool read_float_from_exp(WsCompiler *compiler, WsBuffer *buffer, WsFloat *result)
Definition: wslexer.c:960
#define tVOID
Definition: wsgram.c:249
#define tEXPORT
Definition: wsgram.c:259
#define WS_IS_IDENTIFIER_LETTER(ch)
Definition: wslexer.c:108
static WsUInt32 buffer_to_int(WsCompilerPtr compiler, WsBuffer *buffer)
Definition: wslexer.c:910
int ws_yy_lex(YYSTYPE *yylval, YYLTYPE *yylloc, WsCompiler *compiler)
Definition: wslexer.c:223
#define tIDIV
Definition: wsgram.c:221
#define tRSZSHIFT
Definition: wsgram.c:281
#define WS_IS_NON_ZERO_DIGIT(ch)
Definition: wslexer.c:85
#define tADDA
Definition: wsgram.c:282
void * ws_malloc(size_t size)
Definition: wsalloc.c:77
char * name
Definition: wslexer.c:157
#define tANDA
Definition: wsgram.c:286
void ws_src_error(WsCompilerPtr compiler, WsUInt32 line, char *message,...)
Definition: wserror.c:145
#define tDEBUGGER
Definition: wsgram.c:255
#define COMPILER_MAGIC
Definition: wsint.h:185
#define tDEFAULT
Definition: wsgram.c:256
void ws_error_memory(WsCompilerPtr compiler)
Definition: wserror.c:107
unsigned char * ws_buffer_ptr(WsBuffer *buffer)
Definition: wsbuffer.c:133
#define tSTRUCT
Definition: wsgram.c:266
#define tCONTINUE
Definition: wsgram.c:220
#define tTHIS
Definition: wsgram.c:248
#define tSUPER
Definition: wsgram.c:267
#define tCASE
Definition: wsgram.c:251
#define tSTRING
Definition: wsgram.c:215
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.