wslexer.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:33k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  *
  3.  * wslexer.c
  4.  *
  5.  * Author: Markku Rossi <mtr@iki.fi>
  6.  *
  7.  * Copyright (c) 1999-2000 WAPIT OY LTD.
  8.  *  All rights reserved.
  9.  *
  10.  * Lexical analyzer.
  11.  *
  12.  */
  13. #include "wsint.h"
  14. #include "wsstree.h"
  15. #include "wsgram.h"
  16. /********************* Types and definitions ****************************/
  17. /* A predicate to check whether the character `ch' is a decimal
  18.    digit. */
  19. #define WS_IS_DECIMAL_DIGIT(ch) ('0' <= (ch) && (ch) <= '9')
  20. /* Convert the decimal digit `ch' to an integer number. */
  21. #define WS_DECIMAL_TO_INT(ch) ((ch) - '0')
  22. /* A predicate to check whether the character `ch' is a non-zero
  23.    decimal digit. */
  24. #define WS_IS_NON_ZERO_DIGIT(ch) ('1' <= (ch) && (ch) <= '9')
  25. /* A predicate to check whether the character `ch' is an octal digit. */
  26. #define WS_IS_OCTAL_DIGIT(ch) ('0' <= (ch) && (ch) <= '7')
  27. /* Convert the octal digit `ch' to an integer number. */
  28. #define WS_OCTAL_TO_INT(ch) ((ch) - '0')
  29. /* A predicate to check whether the character `ch' is a hex digit. */
  30. #define WS_IS_HEX_DIGIT(ch) (('0' <= (ch) && (ch) <= '9')
  31.                              || ('a' <= (ch) && (ch) <= 'f')
  32.                              || ('A' <= (ch) && (ch) <= 'F'))
  33. /* Convert the hex digit `ch' to an integer number. */
  34. #define WS_HEX_TO_INT(ch)
  35.     ('0' <= (ch) && (ch) <= '9'
  36.      ? ((ch) - '0')
  37.      : ('a' <= (ch) && (ch) <= 'f'
  38.        ? ((ch) - 'a' + 10)
  39.        : (ch) - 'A' + 10))
  40. /* A predicate to check whether the character `ch' is an identifier
  41.    starter letter. */
  42. #define WS_IS_IDENTIFIER_LETTER(ch)
  43.     (('a' <= (ch) && (ch) <= 'z')
  44.      || ('A' <= (ch) && (ch) <= 'Z')
  45.      || (ch) == '_')
  46. /********************* Prototypes for static functions ******************/
  47. /* Check whether the identifier `id', `len' is a keyword.  If the
  48.    identifier is a keyword, the function returns WS_TRUE and sets the
  49.    keywords token ID to `token_return'.  Otherwise the function
  50.    returns WS_FALSE. */
  51. static WsBool lookup_keyword(char *id, size_t len, int *token_return);
  52. /* Convert literal integer number, stored to the buffer `buffer', into
  53.    a 32 bit integer number.  The function will report possible integer
  54.    overflows to the compiler `compiler'.  The function modifies the
  55.    contents of the buffer `buffer' but it does not free it. */
  56. static WsUInt32 buffer_to_int(WsCompilerPtr compiler, WsBuffer *buffer);
  57. /* Read a floating point number from the decimal point to the buffer
  58.    `buffer'.  The buffer `buffer' might already contain some leading
  59.    digits of the number and it always contains the decimal point.  If
  60.    the operation is successful, the function returns WS_TRUE and it
  61.    returns the resulting floating point number in `result'.  Otherwise
  62.    the function returns WS_FALSE.  The buffer `buffer' must be
  63.    initialized before this function is called and it must be
  64.    uninitialized by the caller. */
  65. static WsBool read_float_from_point(WsCompiler *compiler, WsBuffer *buffer,
  66.                                     WsFloat *result);
  67. /* Read a floating point number from the exponent part to the buffer
  68.    `buffer'.  The buffer might already contain some leading digits and
  69.    fields of the floating poit number.  Otherwise, the function works
  70.    like read_float_from_point(). */
  71. static WsBool read_float_from_exp(WsCompiler *compiler, WsBuffer *buffer,
  72.                                   WsFloat *result);
  73. /********************* Static variables *********************************/
  74. /* A helper macro which expands to a strings and its length excluding
  75.    the trailing '' character. */
  76. #define N(n) n, sizeof(n) - 1
  77. /* They keywords of the WMLScript language.  This array must be sorted
  78.    by the keyword names. */
  79. static struct
  80. {
  81.     char *name;
  82.     size_t name_len;
  83.     int token;
  84. } keywords[] = {
  85.         {N("access"), tACCESS},
  86.         {N("agent"), tAGENT},
  87.         {N("break"), tBREAK},
  88.         {N("case"), tCASE},
  89.         {N("catch"), tCATCH},
  90.         {N("class"), tCLASS},
  91.         {N("const"), tCONST},
  92.         {N("continue"), tCONTINUE},
  93.         {N("debugger"), tDEBUGGER},
  94.         {N("default"), tDEFAULT},
  95.         {N("delete"), tDELETE},
  96.         {N("div"), tIDIV},
  97.         {N("do"), tDO},
  98.         {N("domain"), tDOMAIN},
  99.         {N("else"), tELSE},
  100.         {N("enum"), tENUM},
  101.         {N("equiv"), tEQUIV},
  102.         {N("export"), tEXPORT},
  103.         {N("extends"), tEXTENDS},
  104.         {N("extern"), tEXTERN},
  105.         {N("false"), tFALSE},
  106.         {N("finally"), tFINALLY},
  107.         {N("for"), tFOR},
  108.         {N("function"), tFUNCTION},
  109.         {N("header"), tHEADER},
  110.         {N("http"), tHTTP},
  111.         {N("if"), tIF},
  112.         {N("import"), tIMPORT},
  113.         {N("in"), tIN},
  114.         {N("invalid"), tINVALID},
  115.         {N("isvalid"), tISVALID},
  116.         {N("lib"), tLIB},
  117.         {N("meta"), tMETA},
  118.         {N("name"), tNAME},
  119.         {N("new"), tNEW},
  120.         {N("null"), tNULL},
  121.         {N("path"), tPATH},
  122.         {N("private"), tPRIVATE},
  123.         {N("public"), tPUBLIC},
  124.         {N("return"), tRETURN},
  125.         {N("sizeof"), tSIZEOF},
  126.         {N("struct"), tSTRUCT},
  127.         {N("super"), tSUPER},
  128.         {N("switch"), tSWITCH},
  129.         {N("this"), tTHIS},
  130.         {N("throw"), tTHROW},
  131.         {N("true"), tTRUE},
  132.         {N("try"), tTRY},
  133.         {N("typeof"), tTYPEOF},
  134.         {N("url"), tURL},
  135.         {N("use"), tUSE},
  136.         {N("user"), tUSER},
  137.         {N("var"), tVAR},
  138.         {N("void"), tVOID},
  139.         {N("while"), tWHILE},
  140.         {N("with"), tWITH},
  141. };
  142. static int num_keywords = sizeof(keywords) / sizeof(keywords[0]);
  143. /********************* Global functions *********************************/
  144. int ws_yy_lex(YYSTYPE *yylval, YYLTYPE *yylloc, void *context)
  145. {
  146.     WsCompiler *compiler = (WsCompiler *) context;
  147.     WsUInt32 ch, ch2;
  148.     WsBuffer buffer;
  149.     unsigned char *p;
  150.     WsBool success;
  151.     /* Just check that we get the correct amount of arguments. */
  152.     gw_assert(compiler->magic == COMPILER_MAGIC);
  153.     while (ws_stream_getc(compiler->input, &ch)) {
  154.         /* Save the token's line number. */
  155.         yylloc->first_line = compiler->linenum;
  156.         switch (ch) {
  157.         case 't':  /* Whitespace characters. */
  158.         case 'v':
  159.         case 'f':
  160.         case ' ':
  161.             continue;
  162.         case 'n':  /* Line terminators. */
  163.         case 'r':
  164.             if (ch == 'r' && ws_stream_getc(compiler->input, &ch2)) {
  165.                 if (ch2 != 'n')
  166.                     ws_stream_ungetc(compiler->input, ch2);
  167.             }
  168.             compiler->linenum++;
  169.             continue;
  170.         case '!':  /* !, != */
  171.             if (ws_stream_getc(compiler->input, &ch2)) {
  172.                 if (ch2 == '=')
  173.                     return tNE;
  174.                 ws_stream_ungetc(compiler->input, ch2);
  175.             }
  176.             return '!';
  177.         case '%':  /* %, %= */
  178.             if (ws_stream_getc(compiler->input, &ch2)) {
  179.                 if (ch2 == '=')
  180.                     return tREMA;
  181.                 ws_stream_ungetc(compiler->input, ch2);
  182.             }
  183.             return '%';
  184.         case '&':  /* &, &&, &= */
  185.             if (ws_stream_getc(compiler->input, &ch2)) {
  186.                 if (ch2 == '&')
  187.                     return tAND;
  188.                 if (ch2 == '=')
  189.                     return tANDA;
  190.                 ws_stream_ungetc(compiler->input, ch2);
  191.             }
  192.             return '&';
  193.         case '*':  /* *, *= */
  194.             if (ws_stream_getc(compiler->input, &ch2)) {
  195.                 if (ch2 == '=')
  196.                     return tMULA;
  197.                 ws_stream_ungetc(compiler->input, ch2);
  198.             }
  199.             return '*';
  200.         case '+':  /* +, ++, += */
  201.             if (ws_stream_getc(compiler->input, &ch2)) {
  202.                 if (ch2 == '+')
  203.                     return tPLUSPLUS;
  204.                 if (ch2 == '=')
  205.                     return tADDA;
  206.                 ws_stream_ungetc(compiler->input, ch2);
  207.             }
  208.             return '+';
  209.         case '-':  /* -, --, -= */
  210.             if (ws_stream_getc(compiler->input, &ch2)) {
  211.                 if (ch2 == '-')
  212.                     return tMINUSMINUS;
  213.                 if (ch2 == '=')
  214.                     return tSUBA;
  215.                 ws_stream_ungetc(compiler->input, ch2);
  216.             }
  217.             return '-';
  218.         case '.':
  219.             if (ws_stream_getc(compiler->input, &ch2)) {
  220.                 if (WS_IS_DECIMAL_DIGIT(ch2)) {
  221.                     /* DecimalFloatLiteral. */
  222.                     ws_buffer_init(&buffer);
  223.                     if (!ws_buffer_append_space(&buffer, &p, 2)) {
  224.                         ws_error_memory(compiler);
  225.                         ws_buffer_uninit(&buffer);
  226.                         return EOF;
  227.                     }
  228.                     p[0] = '.';
  229.                     p[1] = (unsigned char) ch2;
  230.                     success = read_float_from_point(compiler, &buffer,
  231.                                                     &yylval->vfloat);
  232.                     ws_buffer_uninit(&buffer);
  233.                     if (!success)
  234.                         return EOF;
  235.                     return tFLOAT;
  236.                 }
  237.                 ws_stream_ungetc(compiler->input, ch2);
  238.             }
  239.             return '.';
  240.         case '/':  /* /, /=, block or a single line comment */
  241.             if (ws_stream_getc(compiler->input, &ch2)) {
  242.                 if (ch2 == '*') {
  243.                     /* Block comment. */
  244.                     while (1) {
  245.                         if (!ws_stream_getc(compiler->input, &ch)) {
  246.                             ws_src_error(compiler, 0, "EOF in comment");
  247.                             return EOF;
  248.                         }
  249.                         if (ch == 'n' || ch == 'r') {
  250.                             /* Line terminators. */
  251.                             if (ch == 'r' && ws_stream_getc(compiler->input,
  252.                                                              &ch2)) {
  253.                                 if (ch2 != 'n')
  254.                                     ws_stream_ungetc(compiler->input, ch2);
  255.                             }
  256.                             compiler->linenum++;
  257.                             /* Continue reading the block comment. */
  258.                             continue;
  259.                         }
  260.                         if (ch == '*' && ws_stream_getc(compiler->input, &ch2)) {
  261.                             if (ch2 == '/')
  262.                                 /* The end of the comment found. */
  263.                                 break;
  264.                             ws_stream_ungetc(compiler->input, ch2);
  265.                         }
  266.                     }
  267.                     /* Continue after the comment. */
  268.                     continue;
  269.                 }
  270.                 if (ch2 == '/') {
  271.                     /* Single line comment. */
  272.                     while (1) {
  273.                         if (!ws_stream_getc(compiler->input, &ch))
  274.                             /* The end of input stream reached.  We accept
  275.                                this as a valid comment terminator. */
  276.                             break;
  277.                         if (ch == 'n' || ch == 'r') {
  278.                             /* Line terminators. */
  279.                             if (ch == 'r' && ws_stream_getc(compiler->input,
  280.                                                              &ch2)) {
  281.                                 if (ch2 != 'n')
  282.                                     ws_stream_ungetc(compiler->input, ch2);
  283.                             }
  284.                             /* The end of the line (and the comment)
  285.                                                     reached. */
  286.                             compiler->linenum++;
  287.                             break;
  288.                         }
  289.                     }
  290.                     /* Continue after the comment. */
  291.                     continue;
  292.                 }
  293.                 if (ch2 == '=')
  294.                     return tDIVA;
  295.                 ws_stream_ungetc(compiler->input, ch2);
  296.             }
  297.             return '/';
  298.         case '<':  /* <, <<, <<=, <= */
  299.             if (ws_stream_getc(compiler->input, &ch2)) {
  300.                 if (ch2 == '<') {
  301.                     if (ws_stream_getc(compiler->input, &ch2)) {
  302.                         if (ch2 == '=')
  303.                             return tLSHIFTA;
  304.                         ws_stream_ungetc(compiler->input, ch2);
  305.                     }
  306.                     return tLSHIFT;
  307.                 }
  308.                 if (ch2 == '=')
  309.                     return tLE;
  310.                 ws_stream_ungetc(compiler->input, ch2);
  311.             }
  312.             return '<';
  313.         case '=':  /* =, == */
  314.             if (ws_stream_getc(compiler->input, &ch2)) {
  315.                 if (ch2 == '=')
  316.                     return tEQ;
  317.                 ws_stream_ungetc(compiler->input, ch2);
  318.             }
  319.             return '=';
  320.         case '>':  /* >, >=, >>, >>=, >>>, >>>= */
  321.             if (ws_stream_getc(compiler->input, &ch2)) {
  322.                 if (ch2 == '>') {
  323.                     if (ws_stream_getc(compiler->input, &ch2)) {
  324.                         if (ch2 == '>') {
  325.                             if (ws_stream_getc(compiler->input, &ch2)) {
  326.                                 if (ch2 == '=')
  327.                                     return tRSZSHIFTA;
  328.                                 ws_stream_ungetc(compiler->input, ch2);
  329.                             }
  330.                             return tRSZSHIFT;
  331.                         }
  332.                         if (ch2 == '=')
  333.                             return tRSSHIFTA;
  334.                         ws_stream_ungetc(compiler->input, ch2);
  335.                     }
  336.                     return tRSSHIFT;
  337.                 }
  338.                 if (ch2 == '=')
  339.                     return tGE;
  340.                 ws_stream_ungetc(compiler->input, ch2);
  341.             }
  342.             return '>';
  343.         case '^':  /* ^, ^= */
  344.             if (ws_stream_getc(compiler->input, &ch2)) {
  345.                 if (ch2 == '=')
  346.                     return tXORA;
  347.                 ws_stream_ungetc(compiler->input, ch2);
  348.             }
  349.             return '^';
  350.         case '|':  /* |, |=, || */
  351.             if (ws_stream_getc(compiler->input, &ch2)) {
  352.                 if (ch2 == '=')
  353.                     return tORA;
  354.                 if (ch2 == '|')
  355.                     return tOR;
  356.                 ws_stream_ungetc(compiler->input, ch2);
  357.             }
  358.             return '|';
  359.         case '#':  /* The simple cases. */
  360.         case '(':
  361.         case ')':
  362.         case ',':
  363.         case ':':
  364.         case ';':
  365.         case '?':
  366.         case '{':
  367.         case '}':
  368.         case '~':
  369.             return (int) ch;
  370.         case ''':  /* String literals. */
  371.         case '"':
  372.             {
  373.                 WsUInt32 string_end_ch = ch;
  374.                 WsUtf8String *str = ws_utf8_alloc();
  375.                 if (str == NULL) {
  376.                     ws_error_memory(compiler);
  377.                     return EOF;
  378.                 }
  379.                 while (1) {
  380.                     if (!ws_stream_getc(compiler->input, &ch)) {
  381. eof_in_string_literal:
  382.                         ws_src_error(compiler, 0, "EOF in string literal");
  383.                         ws_utf8_free(str);
  384.                         return EOF;
  385.                     }
  386.                     if (ch == string_end_ch)
  387.                         /* The end of string reached. */
  388.                         break;
  389.                     if (ch == '\') {
  390.                         /* An escape sequence. */
  391.                         if (!ws_stream_getc(compiler->input, &ch))
  392.                             goto eof_in_string_literal;
  393.                         switch (ch) {
  394.                         case ''':
  395.                         case '"':
  396.                         case '\':
  397.                         case '/':
  398.                             /* The character as-is. */
  399.                             break;
  400.                         case 'b':
  401.                             ch = 'b';
  402.                             break;
  403.                         case 'f':
  404.                             ch = 'f';
  405.                             break;
  406.                         case 'n':
  407.                             ch = 'n';
  408.                             break;
  409.                         case 'r':
  410.                             ch = 'r';
  411.                             break;
  412.                         case 't':
  413.                             ch = 't';
  414.                             break;
  415.                         case 'x':
  416.                         case 'u':
  417.                             {
  418.                                 int i, len;
  419.                                 int type = ch;
  420.                                 if (ch == 'x')
  421.                                     len = 2;
  422.                                 else
  423.                                     len = 4;
  424.                                 ch = 0;
  425.                                 for (i = 0; i < len; i++) {
  426.                                     if (!ws_stream_getc(compiler->input, &ch2))
  427.                                         goto eof_in_string_literal;
  428.                                     if (!WS_IS_HEX_DIGIT(ch2)) {
  429.                                         ws_src_error(compiler, 0,
  430.                                                      "malformed `\%c' escape in "
  431.                                                      "string literal", (char) type);
  432.                                         ch = 0;
  433.                                         break;
  434.                                     }
  435.                                     ch *= 16;
  436.                                     ch += WS_HEX_TO_INT(ch2);
  437.                                 }
  438.                             }
  439.                             break;
  440.                         default:
  441.                             if (WS_IS_OCTAL_DIGIT(ch)) {
  442.                                 int i;
  443.                                 int limit = 3;
  444.                                 ch = WS_OCTAL_TO_INT(ch);
  445.                                 if (ch > 3)
  446.                                     limit = 2;
  447.                                 for (i = 1; i < limit; i++) {
  448.                                     if (!ws_stream_getc(compiler->input, &ch2))
  449.                                         goto eof_in_string_literal;
  450.                                     if (!WS_IS_OCTAL_DIGIT(ch2)) {
  451.                                         ws_stream_ungetc(compiler->input, ch2);
  452.                                         break;
  453.                                     }
  454.                                     ch *= 8;
  455.                                     ch += WS_OCTAL_TO_INT(ch2);
  456.                                 }
  457.                             } else {
  458.                                 ws_src_error(compiler, 0,
  459.                                              "unknown escape sequence `\%c' in "
  460.                                              "string literal", (char) ch);
  461.                                 ch = 0;
  462.                             }
  463.                             break;
  464.                         }
  465.                         /* FALLTHROUGH */
  466.                     }
  467.                     if (!ws_utf8_append_char(str, ch)) {
  468.                         ws_error_memory(compiler);
  469.                         ws_utf8_free(str);
  470.                         return EOF;
  471.                     }
  472.                 }
  473.                 if (!ws_lexer_register_utf8(compiler, str)) {
  474.                     ws_error_memory(compiler);
  475.                     ws_utf8_free(str);
  476.                     return EOF;
  477.                 }
  478.                 gw_assert(str != NULL);
  479.                 yylval->string = str;
  480.                 return tSTRING;
  481.             }
  482.             break;
  483.         default:
  484.             /* Identifiers, keywords and number constants. */
  485.             if (WS_IS_IDENTIFIER_LETTER(ch)) {
  486.                 WsBool got;
  487.                 int token;
  488.                 unsigned char *p;
  489.                 unsigned char *np;
  490.                 size_t len = 0;
  491.                 /* An identifier or a keyword.  We start with a 256
  492.                  * bytes long buffer but it is expanded dynamically if
  493.                  * needed.  However, 256 should be enought for most
  494.                  * cases since the byte-code format limits the function
  495.                  * names to 255 characters. */
  496.                 p = ws_malloc(256);
  497.                 if (p == NULL) {
  498.                     ws_error_memory(compiler);
  499.                     return EOF;
  500.                 }
  501.                 do {
  502.                     /* Add one extra for the possible terminator
  503.                        character. */
  504.                     np = ws_realloc(p, len + 2);
  505.                     if (np == NULL) {
  506.                         ws_error_memory(compiler);
  507.                         ws_free(p);
  508.                         return EOF;
  509.                     }
  510.                     p = np;
  511.                     /* This is ok since the only valid identifier names
  512.                      * can be written in 7 bit ASCII. */
  513.                     p[len++] = (unsigned char) ch;
  514.                 } while ((got = ws_stream_getc(compiler->input, &ch))
  515.                          && (WS_IS_IDENTIFIER_LETTER(ch)
  516.                              || WS_IS_DECIMAL_DIGIT(ch)));
  517.                 if (got)
  518.                     /* Put back the terminator character. */
  519.                     ws_stream_ungetc(compiler->input, ch);
  520.                 /* Is it a keyword? */
  521.                 if (lookup_keyword((char *) p, len, &token)) {
  522.                     /* Yes it is... */
  523.                     ws_free(p);
  524.                     /* ...except one case: `div='. */
  525.                     if (token == tIDIV) {
  526.                         if (ws_stream_getc(compiler->input, &ch)) {
  527.                             if (ch == '=')
  528.                                 return tIDIVA;
  529.                             ws_stream_ungetc(compiler->input, ch);
  530.                         }
  531.                     }
  532.                     /* Return the token value. */
  533.                     return token;
  534.                 }
  535.                 /* It is a normal identifier.  Let's pad the name with a
  536.                           null-character.  We have already allocated space for
  537.                           it. */
  538.                 p[len] = '';
  539.                 if (!ws_lexer_register_block(compiler, p)) {
  540.                     ws_error_memory(compiler);
  541.                     ws_free(p);
  542.                     return EOF;
  543.                 }
  544.                 gw_assert(p != NULL);
  545.                 yylval->identifier = (char *) p;
  546.                 return tIDENTIFIER;
  547.             }
  548.             if (WS_IS_NON_ZERO_DIGIT(ch)) {
  549.                 /* A decimal integer literal or a decimal float
  550.                           literal. */
  551.                 ws_buffer_init(&buffer);
  552.                 if (!ws_buffer_append_space(&buffer, &p, 1)) {
  553. number_error_memory:
  554.                     ws_error_memory(compiler);
  555.                     ws_buffer_uninit(&buffer);
  556.                     return EOF;
  557.                 }
  558.                 p[0] = ch;
  559.                 while (ws_stream_getc(compiler->input, &ch)) {
  560.                     if (WS_IS_DECIMAL_DIGIT(ch)) {
  561.                         if (!ws_buffer_append_space(&buffer, &p, 1))
  562.                             goto number_error_memory;
  563.                         p[0] = ch;
  564.                     } else if (ch == '.' || ch == 'e' || ch == 'E') {
  565.                         /* DecimalFloatLiteral. */
  566.                         if (ch == '.') {
  567.                             if (!ws_buffer_append_space(&buffer, &p, 1))
  568.                                 goto number_error_memory;
  569.                             p[0] = '.';
  570.                             success = read_float_from_point(compiler, &buffer,
  571.                                                             &yylval->vfloat);
  572.                         } else {
  573.                             ws_stream_ungetc(compiler->input, ch);
  574.                             success = read_float_from_exp(compiler, &buffer,
  575.                                                           &yylval->vfloat);
  576.                         }
  577.                         ws_buffer_uninit(&buffer);
  578.                         if (!success)
  579.                             return EOF;
  580.                         return tFLOAT;
  581.                     } else {
  582.                         ws_stream_ungetc(compiler->input, ch);
  583.                         break;
  584.                     }
  585.                 }
  586.                 /* Now the buffer contains an integer number as a
  587.                           string.  Let's convert it to an integer number. */
  588.                 yylval->integer = buffer_to_int(compiler, &buffer);
  589.                 ws_buffer_uninit(&buffer);
  590.                 /* Read a DecimalIntegerLiteral. */
  591.                 return tINTEGER;
  592.             }
  593.             if (ch == '0') {
  594.                 /* The integer constant 0, an octal number or a
  595.                    HexIntegerLiteral. */
  596.                 if (ws_stream_getc(compiler->input, &ch2)) {
  597.                     if (ch2 == 'x' || ch2 == 'X') {
  598.                         /* HexIntegerLiteral. */
  599.                         ws_buffer_init(&buffer);
  600.                         if (!ws_buffer_append_space(&buffer, &p, 2))
  601.                             goto number_error_memory;
  602.                         p[0] = '0';
  603.                         p[1] = 'x';
  604.                         while (ws_stream_getc(compiler->input, &ch)) {
  605.                             if (WS_IS_HEX_DIGIT(ch)) {
  606.                                 if (!ws_buffer_append_space(&buffer, &p, 1))
  607.                                     goto number_error_memory;
  608.                                 p[0] = ch;
  609.                             } else {
  610.                                 ws_stream_ungetc(compiler->input, ch);
  611.                                 break;
  612.                             }
  613.                         }
  614.                         if (ws_buffer_len(&buffer) == 2) {
  615.                             ws_buffer_uninit(&buffer);
  616.                             ws_src_error(compiler, 0,
  617.                                          "numeric constant with no digits");
  618.                             yylval->integer = 0;
  619.                             return tINTEGER;
  620.                         }
  621.                         /* Now the buffer contains an integer number as
  622.                          * a string.  Let's convert it to an integer
  623.                          * number. */
  624.                         yylval->integer = buffer_to_int(compiler, &buffer);
  625.                         ws_buffer_uninit(&buffer);
  626.                         /* Read a HexIntegerLiteral. */
  627.                         return tINTEGER;
  628.                     }
  629.                     if (WS_IS_OCTAL_DIGIT(ch2)) {
  630.                         /* OctalIntegerLiteral. */
  631.                         ws_buffer_init(&buffer);
  632.                         if (!ws_buffer_append_space(&buffer, &p, 2))
  633.                             goto number_error_memory;
  634.                         p[0] = '0';
  635.                         p[1] = ch2;
  636.                         while (ws_stream_getc(compiler->input, &ch)) {
  637.                             if (WS_IS_OCTAL_DIGIT(ch)) {
  638.                                 if (!ws_buffer_append_space(&buffer, &p, 1))
  639.                                     goto number_error_memory;
  640.                                 p[0] = ch;
  641.                             } else {
  642.                                 ws_stream_ungetc(compiler->input, ch);
  643.                                 break;
  644.                             }
  645.                         }
  646.                         /* Convert the buffer into an intger number. */
  647.                         yylval->integer = buffer_to_int(compiler, &buffer);
  648.                         ws_buffer_uninit(&buffer);
  649.                         /* Read an OctalIntegerLiteral. */
  650.                         return tINTEGER;
  651.                     }
  652.                     if (ch2 == '.' || ch2 == 'e' || ch2 == 'E') {
  653.                         /* DecimalFloatLiteral. */
  654.                         ws_buffer_init(&buffer);
  655.                         if (ch2 == '.') {
  656.                             if (!ws_buffer_append_space(&buffer, &p, 1))
  657.                                 goto number_error_memory;
  658.                             p[0] = '.';
  659.                             success = read_float_from_point(compiler, &buffer,
  660.                                                             &yylval->vfloat);
  661.                         } else {
  662.                             ws_stream_ungetc(compiler->input, ch);
  663.                             success = read_float_from_exp(compiler, &buffer,
  664.                                                           &yylval->vfloat);
  665.                         }
  666.                         ws_buffer_uninit(&buffer);
  667.                         if (!success)
  668.                             return EOF;
  669.                         return tFLOAT;
  670.                     }
  671.                     ws_stream_ungetc(compiler->input, ch2);
  672.                 }
  673.                 /* Integer literal 0. */
  674.                 yylval->integer = 0;
  675.                 return tINTEGER;
  676.             }
  677.             /* Garbage found from the input stream. */
  678.             ws_src_error(compiler, 0,
  679.                          "garbage found from the input stream: character=0x%x",
  680.                          ch);
  681.             return EOF;
  682.             break;
  683.         }
  684.     }
  685.     return EOF;
  686. }
  687. /********************* Static functions *********************************/
  688. static WsBool lookup_keyword(char *id, size_t len, int *token_return)
  689. {
  690.     int left = 0, center, right = num_keywords;
  691.     while (left < right) {
  692.         size_t l;
  693.         int result;
  694.         center = left + (right - left) / 2;
  695.         l = keywords[center].name_len;
  696.         if (len < l)
  697.             l = len;
  698.         result = memcmp(id, keywords[center].name, l);
  699.         if (result < 0 || (result == 0 && len < keywords[center].name_len))
  700.             /* The possible match is smaller. */
  701.             right = center;
  702.         else if (result > 0 || (result == 0 && len > keywords[center].name_len))
  703.             /* The possible match is bigger. */
  704.             left = center + 1;
  705.         else {
  706.             /* Found a match. */
  707.             *token_return = keywords[center].token;
  708.             return WS_TRUE;
  709.         }
  710.     }
  711.     /* No match. */
  712.     return WS_FALSE;
  713. }
  714. static WsUInt32 buffer_to_int(WsCompilerPtr compiler, WsBuffer *buffer)
  715. {
  716.     unsigned char *p;
  717.     unsigned long value;
  718.     /* Terminate the string. */
  719.     if (!ws_buffer_append_space(buffer, &p, 1)) {
  720.         ws_error_memory(compiler);
  721.         return 0;
  722.     }
  723.     p[0] = '';
  724.     /* Convert the buffer into an integer number.  The base is taken
  725.        from the bufer. */
  726.     errno = 0;
  727.     value = strtoul((char *) ws_buffer_ptr(buffer), NULL, 0);
  728.     /* Check for overflow.  We accept WS_INT32_MAX + 1 because we might
  729.      * be parsing the numeric part of '-2147483648'. */
  730.     if (errno == ERANGE || value > (WsUInt32) WS_INT32_MAX + 1)
  731.         ws_src_error(compiler, 0, "integer literal too large");
  732.     /* All done. */
  733.     return (WsUInt32) value;
  734. }
  735. static WsBool read_float_from_point(WsCompiler *compiler, WsBuffer *buffer,
  736.                                     WsFloat *result)
  737. {
  738.     WsUInt32 ch;
  739.     unsigned char *p;
  740.     while (ws_stream_getc(compiler->input, &ch)) {
  741.         if (WS_IS_DECIMAL_DIGIT(ch)) {
  742.             if (!ws_buffer_append_space(buffer, &p, 1)) {
  743.                 ws_error_memory(compiler);
  744.                 return WS_FALSE;
  745.             }
  746.             p[0] = (unsigned char) ch;
  747.         } else {
  748.             ws_stream_ungetc(compiler->input, ch);
  749.             break;
  750.         }
  751.     }
  752.     return read_float_from_exp(compiler, buffer, result);
  753. }
  754. static WsBool read_float_from_exp(WsCompiler *compiler, WsBuffer *buffer,
  755.                                   WsFloat *result)
  756. {
  757.     WsUInt32 ch;
  758.     unsigned char *p;
  759.     int sign = '+';
  760.     unsigned char buf[4];
  761.     /* Do we have an exponent part. */
  762.     if (!ws_stream_getc(compiler->input, &ch))
  763.         goto done;
  764.     if (ch != 'e' && ch != 'E') {
  765.         /* No exponent part. */
  766.         ws_stream_ungetc(compiler->input, ch);
  767.         goto done;
  768.     }
  769.     /* Sign. */
  770.     if (!ws_stream_getc(compiler->input, &ch)) {
  771.         /* This is an error. */
  772.         ws_src_error(compiler, 0, "truncated float literal");
  773.         return WS_FALSE;
  774.     }
  775.     if (ch == '-')
  776.         sign = '-';
  777.     else if (ch == '+')
  778.         sign = '+';
  779.     else
  780.         ws_stream_ungetc(compiler->input, ch);
  781.     /* DecimalDigits. */
  782.     if (!ws_stream_getc(compiler->input, &ch)) {
  783.         ws_src_error(compiler, 0, "truncated float literal");
  784.         return WS_FALSE;
  785.     }
  786.     if (!WS_IS_DECIMAL_DIGIT(ch)) {
  787.         ws_src_error(compiler, 0, "no decimal digits in exponent part");
  788.         return WS_FALSE;
  789.     }
  790.     /* Append exponent part read so far. */
  791.     if (!ws_buffer_append_space(buffer, &p, 2)) {
  792.         ws_error_memory(compiler);
  793.         return WS_FALSE;
  794.     }
  795.     p[0] = 'e';
  796.     p[1] = sign;
  797.     /* Read decimal digits. */
  798.     while (WS_IS_DECIMAL_DIGIT(ch)) {
  799.         if (!ws_buffer_append_space(buffer, &p, 1)) {
  800.             ws_error_memory(compiler);
  801.             return WS_FALSE;
  802.         }
  803.         p[0] = (unsigned char) ch;
  804.         if (!ws_stream_getc(compiler->input, &ch))
  805.             /* EOF.  This is ok. */
  806.             goto done;
  807.     }
  808.     /* Unget the extra character. */
  809.     ws_stream_ungetc(compiler->input, ch);
  810.     /* FALLTHROUGH */
  811. done:
  812.     if (!ws_buffer_append_space(buffer, &p, 1)) {
  813.         ws_error_memory(compiler);
  814.         return WS_FALSE;
  815.     }
  816.     p[0] = 0;
  817.     /* Now the buffer contains a valid floating point number. */
  818.     *result = (WsFloat) strtod((char *) ws_buffer_ptr(buffer), NULL);
  819.     /* Check that the generated floating point number fits to
  820.        `float32'. */
  821.     if (*result == HUGE_VAL || *result == -HUGE_VAL
  822.         || ws_ieee754_encode_single(*result, buf) != WS_IEEE754_OK)
  823.         ws_src_error(compiler, 0, "floating point literal too large");
  824.     return WS_TRUE;
  825. }