userspace/kp_lex.c - ktap

Global variables defined

Functions defined

Macros defined

Source code

  1. /*
  2. * Lexical analyzer.
  3. *
  4. * This file is part of ktap by Jovi Zhangwei.
  5. *
  6. * Copyright (C) 2012-2014 Jovi Zhangwei <jovi.zhangwei@gmail.com>.
  7. *
  8. * Adapted from luajit and lua interpreter.
  9. * Copyright (C) 2005-2014 Mike Pall.
  10. * Copyright (C) 1994-2008 Lua.org, PUC-Rio.
  11. *
  12. * ktap is free software; you can redistribute it and/or modify it
  13. * under the terms and conditions of the GNU General Public License,
  14. * version 2, as published by the Free Software Foundation.
  15. *
  16. * ktap is distributed in the hope it will be useful, but WITHOUT
  17. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  18. * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  19. * more details.
  20. *
  21. * You should have received a copy of the GNU General Public License along with
  22. * this program; if not, write to the Free Software Foundation, Inc.,
  23. * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  24. */

  25. #include "../include/ktap_types.h"
  26. #include "../include/ktap_err.h"
  27. #include "kp_util.h"
  28. #include "kp_lex.h"
  29. #include "kp_parse.h"

  30. /* lexer token names. */
  31. static const char *const tokennames[] = {
  32. #define TKSTR1(name)        #name,
  33. #define TKSTR2(name, sym)    #sym,
  34. TKDEF(TKSTR1, TKSTR2)
  35. #undef TKSTR1
  36. #undef TKSTR2
  37.   NULL
  38. };

  39. /* -- Buffer handling ----------------------------------------------------- */

  40. #define LEX_EOF            (-1)
  41. #define lex_iseol(ls)        (ls->c == '\n' || ls->c == '\r')

  42. /* Get next character. */
  43. static inline LexChar lex_next(LexState *ls)
  44. {
  45.     return (ls->c = ls->p < ls->pe ? (LexChar)(uint8_t)*ls->p++ : LEX_EOF);
  46. }

  47. /* Save character. */
  48. static inline void lex_save(LexState *ls, LexChar c)
  49. {
  50.     kp_buf_putb(&ls->sb, c);
  51. }

  52. /* Save previous character and get next character. */
  53. static inline LexChar lex_savenext(LexState *ls)
  54. {
  55.     lex_save(ls, ls->c);
  56.     return lex_next(ls);
  57. }

  58. /* Skip line break. Handles "\n", "\r", "\r\n" or "\n\r". */
  59. static void lex_newline(LexState *ls)
  60. {
  61.     LexChar old = ls->c;

  62.     kp_assert(lex_iseol(ls));
  63.     lex_next(ls);  /* Skip "\n" or "\r". */
  64.     if (lex_iseol(ls) && ls->c != old)
  65.         lex_next(ls);  /* Skip "\n\r" or "\r\n". */
  66.     if (++ls->linenumber >= KP_MAX_LINE)
  67.         kp_lex_error(ls, ls->tok, KP_ERR_XLINES);
  68. }

  69. /* -- Scanner for terminals ----------------------------------------------- */

  70. static int kp_str2d(const char *s, size_t len, ktap_number *result)
  71. {
  72.     char *endptr;

  73.     if (strpbrk(s, "nN"))  /* reject 'inf' and 'nan' */
  74.         return 0;
  75.     else
  76.         *result = (long)strtoul(s, &endptr, 0);

  77.     if (endptr == s)
  78.         return 0/* nothing recognized */
  79.     while (kp_char_isspace((unsigned char)(*endptr)))
  80.         endptr++;
  81.     return (endptr == s + len);  /* OK if no trailing characters */
  82. }


  83. /* Parse a number literal. */
  84. static void lex_number(LexState *ls, ktap_val_t *tv)
  85. {
  86.     LexChar c, xp = 'e';
  87.     ktap_number n = 0;

  88.     kp_assert(kp_char_isdigit(ls->c));
  89.     if ((c = ls->c) == '0' && (lex_savenext(ls) | 0x20) == 'x')
  90.         xp = 'p';
  91.     while (kp_char_isident(ls->c) || ls->c == '.' ||
  92.         ((ls->c == '-' || ls->c == '+') && (c | 0x20) == xp)) {
  93.         c = ls->c;
  94.         lex_savenext(ls);
  95.     }
  96.     lex_save(ls, '\0');
  97.     if (!kp_str2d(sbufB(&ls->sb), sbuflen(&ls->sb) - 1, &n))
  98.             kp_lex_error(ls, ls->tok, KP_ERR_XNUMBER);
  99.     set_number(tv, n);
  100. }

  101. /* Skip equal signs for "[=...=[" and "]=...=]" and return their count. */
  102. static int lex_skipeq(LexState *ls)
  103. {
  104.     int count = 0;
  105.     LexChar s = ls->c;

  106.     kp_assert(s == '[' || s == ']');
  107.     while (lex_savenext(ls) == '=')
  108.         count++;
  109.     return (ls->c == s) ? count : (-count) - 1;
  110. }

  111. /* Parse a long string or long comment (tv set to NULL). */
  112. static void lex_longstring(LexState *ls, ktap_val_t *tv, int sep)
  113. {
  114.     lex_savenext(ls);  /* Skip second '['. */
  115.     if (lex_iseol(ls))  /* Skip initial newline. */
  116.         lex_newline(ls);
  117.     for (;;) {
  118.         switch (ls->c) {
  119.         case LEX_EOF:
  120.             kp_lex_error(ls, TK_eof,
  121.                     tv ? KP_ERR_XLSTR : KP_ERR_XLCOM);
  122.             break;
  123.         case ']':
  124.             if (lex_skipeq(ls) == sep) {
  125.                 lex_savenext(ls);  /* Skip second ']'. */
  126.                 goto endloop;
  127.             }
  128.             break;
  129.         case '\n':
  130.         case '\r':
  131.             lex_save(ls, '\n');
  132.             lex_newline(ls);
  133.             if (!tv) /* Don't waste space for comments. */
  134.                 kp_buf_reset(&ls->sb);
  135.             break;
  136.         default:
  137.             lex_savenext(ls);
  138.             break;
  139.         }
  140.     }
  141. endloop:
  142.     if (tv) {
  143.         ktap_str_t *str = kp_parse_keepstr(ls,
  144.                     sbufB(&ls->sb) + (2 + (int)sep),
  145.                     sbuflen(&ls->sb) - 2*(2 + (int)sep));
  146.         set_string(tv, str);
  147.     }
  148. }

  149. /* Parse a string. */
  150. static void lex_string(LexState *ls, ktap_val_t *tv)
  151. {
  152.     LexChar delim = ls->c;  /* Delimiter is '\'' or '"'. */

  153.     lex_savenext(ls);
  154.     while (ls->c != delim) {
  155.         switch (ls->c) {
  156.         case LEX_EOF:
  157.             kp_lex_error(ls, TK_eof, KP_ERR_XSTR);
  158.             continue;
  159.         case '\n':
  160.         case '\r':
  161.             kp_lex_error(ls, TK_string, KP_ERR_XSTR);
  162.             continue;
  163.         case '\\': {
  164.             LexChar c = lex_next(ls);  /* Skip the '\\'. */
  165.             switch (c) {
  166.             case 'a': c = '\a'; break;
  167.             case 'b': c = '\b'; break;
  168.             case 'f': c = '\f'; break;
  169.             case 'n': c = '\n'; break;
  170.             case 'r': c = '\r'; break;
  171.             case 't': c = '\t'; break;
  172.             case 'v': c = '\v'; break;
  173.             case 'x'/* Hexadecimal escape '\xXX'. */
  174.                 c = (lex_next(ls) & 15u) << 4;
  175.                 if (!kp_char_isdigit(ls->c)) {
  176.                     if (!kp_char_isxdigit(ls->c))
  177.                         goto err_xesc;
  178.                     c += 9 << 4;
  179.                 }
  180.                 c += (lex_next(ls) & 15u);
  181.                 if (!kp_char_isdigit(ls->c)) {
  182.                     if (!kp_char_isxdigit(ls->c))
  183.                         goto err_xesc;
  184.                     c += 9;
  185.                 }
  186.                 break;
  187.             case 'z'/* Skip whitespace. */
  188.                 lex_next(ls);
  189.                 while (kp_char_isspace(ls->c))
  190.                     if (lex_iseol(ls))
  191.                         lex_newline(ls);
  192.                     else
  193.                         lex_next(ls);
  194.                     continue;
  195.             case '\n': case '\r':
  196.                 lex_save(ls, '\n');
  197.                 lex_newline(ls);
  198.                 continue;
  199.             case '\\': case '\"': case '\'':
  200.                 break;
  201.             case LEX_EOF:
  202.                 continue;
  203.             default:
  204.                 if (!kp_char_isdigit(c))
  205.                     goto err_xesc;
  206.                 c -= '0'/* Decimal escape '\ddd'. */
  207.                 if (kp_char_isdigit(lex_next(ls))) {
  208.                     c = c*10 + (ls->c - '0');
  209.                     if (kp_char_isdigit(lex_next(ls))) {
  210.                         c = c*10 + (ls->c - '0');
  211.                         if (c > 255) {
  212. err_xesc:
  213.                             kp_lex_error(ls,
  214.                                 TK_string,
  215.                                 KP_ERR_XESC);
  216.                         }
  217.                         lex_next(ls);
  218.                     }
  219.                 }
  220.                 lex_save(ls, c);
  221.                 continue;
  222.             }
  223.             lex_save(ls, c);
  224.             lex_next(ls);
  225.             continue;
  226.         }
  227.         default:
  228.             lex_savenext(ls);
  229.             break;
  230.         }
  231.     }
  232.     lex_savenext(ls);  /* Skip trailing delimiter. */
  233.     set_string(tv,
  234.         kp_parse_keepstr(ls, sbufB(&ls->sb)+1, sbuflen(&ls->sb)-2));
  235. }

  236. /* lex helper for parse_trace and parse_timer */
  237. void kp_lex_read_string_until(LexState *ls, int c)
  238. {
  239.     ktap_str_t *ts;

  240.     kp_buf_reset(&ls->sb);

  241.     while (ls->c == ' ')
  242.         lex_next(ls);

  243.     do {
  244.         lex_savenext(ls);
  245.     } while (ls->c != c && ls->c != LEX_EOF);

  246.     if (ls->c != c)
  247.         kp_lex_error(ls, ls->tok, KP_ERR_XTOKEN, c);

  248.     ts = kp_parse_keepstr(ls, sbufB(&ls->sb), sbuflen(&ls->sb));
  249.     ls->tok = TK_string;
  250.     set_string(&ls->tokval, ts);
  251. }


  252. /* -- Main lexical scanner ------------------------------------------------ */

  253. /* Get next lexical token. */
  254. static LexToken lex_scan(LexState *ls, ktap_val_t *tv)
  255. {
  256.     kp_buf_reset(&ls->sb);
  257.     for (;;) {
  258.         if (kp_char_isident(ls->c)) {
  259.             ktap_str_t *s;
  260.             if (kp_char_isdigit(ls->c)) {  /* Numeric literal. */
  261.                 lex_number(ls, tv);
  262.                 return TK_number;
  263.             }
  264.             /* Identifier or reserved word. */
  265.             do {
  266.                 lex_savenext(ls);
  267.             } while (kp_char_isident(ls->c));
  268.             s = kp_parse_keepstr(ls, sbufB(&ls->sb),
  269.                         sbuflen(&ls->sb));
  270.             set_string(tv, s);
  271.             if (s->reserved > 0/* Reserved word? */
  272.                 return TK_OFS + s->reserved;
  273.             return TK_name;
  274.         }

  275.         switch (ls->c) {
  276.         case '\n':
  277.         case '\r':
  278.             lex_newline(ls);
  279.             continue;
  280.         case ' ':
  281.         case '\t':
  282.         case '\v':
  283.         case '\f':
  284.             lex_next(ls);
  285.             continue;

  286.         case '#':
  287.             while (!lex_iseol(ls) && ls->c != LEX_EOF)
  288.                 lex_next(ls);
  289.             break;
  290.         case '-':
  291.             lex_next(ls);
  292.             if (ls->c != '-')
  293.                 return '-';
  294.             lex_next(ls);
  295.             if (ls->c == '[') { /* Long comment "--[=*[...]=*]". */
  296.                 int sep = lex_skipeq(ls);
  297.                 /* `lex_skipeq' may dirty the buffer */
  298.                 kp_buf_reset(&ls->sb);
  299.                 if (sep >= 0) {
  300.                     lex_longstring(ls, NULL, sep);
  301.                     kp_buf_reset(&ls->sb);
  302.                     continue;
  303.                 }
  304.             }
  305.             /* Short comment "--.*\n". */
  306.             while (!lex_iseol(ls) && ls->c != LEX_EOF)
  307.                 lex_next(ls);
  308.             continue;
  309.         case '[': {
  310.             int sep = lex_skipeq(ls);
  311.             if (sep >= 0) {
  312.                 lex_longstring(ls, tv, sep);
  313.                 return TK_string;
  314.             } else if (sep == -1) {
  315.                 return '[';
  316.             } else {
  317.                 kp_lex_error(ls, TK_string, KP_ERR_XLDELIM);
  318.                 continue;
  319.             }
  320.         }
  321.         case '+': {
  322.             lex_next(ls);
  323.             if (ls->c != '=')
  324.                 return '+';
  325.             else {
  326.                 lex_next(ls);
  327.                 return TK_incr;
  328.             }
  329.         }
  330.         case '=':
  331.             lex_next(ls);
  332.             if (ls->c != '=')
  333.                 return '=';
  334.             else {
  335.                 lex_next(ls);
  336.                 return TK_eq;
  337.             }
  338.         case '<':
  339.             lex_next(ls);
  340.             if (ls->c != '=')
  341.                 return '<';
  342.             else {
  343.                 lex_next(ls);
  344.                 return TK_le;
  345.             }
  346.         case '>':
  347.             lex_next(ls);
  348.             if (ls->c != '=')
  349.                 return '>';
  350.             else {
  351.                 lex_next(ls);
  352.                 return TK_ge;
  353.             }
  354.         case '!':
  355.                   lex_next(ls);
  356.             if (ls->c != '=')
  357.                 return TK_not;
  358.             else {
  359.                 lex_next(ls);
  360.                 return TK_ne;
  361.             }
  362.         case ':':
  363.             lex_next(ls);
  364.             if (ls->c != ':')
  365.                 return ':';
  366.             else {
  367.                 lex_next(ls);
  368.                 return TK_label;
  369.             }
  370.         case '"':
  371.         case '\'':
  372.             lex_string(ls, tv);
  373.             return TK_string;
  374.         case '.':
  375.             if (lex_savenext(ls) == '.') {
  376.                 lex_next(ls);
  377.                 if (ls->c == '.') {
  378.                     lex_next(ls);
  379.                     return TK_dots;   /* ... */
  380.                 }
  381.                 return TK_concat;   /* .. */
  382.             } else if (!kp_char_isdigit(ls->c)) {
  383.                 return '.';
  384.             } else {
  385.                 lex_number(ls, tv);
  386.                 return TK_number;
  387.             }
  388.         case LEX_EOF:
  389.             return TK_eof;
  390.         case '&':
  391.             lex_next(ls);
  392.             if (ls->c != '&')
  393.                 return '&';
  394.             else {
  395.                 lex_next(ls);
  396.                 return TK_and;
  397.             }
  398.         case '|':
  399.             lex_next(ls);
  400.             if (ls->c != '|')
  401.                 return '|';
  402.             else {
  403.                 lex_next(ls);
  404.                 return TK_or;
  405.             }
  406.         default: {
  407.             LexChar c = ls->c;
  408.             lex_next(ls);
  409.             return c;  /* Single-char tokens (+ - / ...). */
  410.         }
  411.         }
  412.     }
  413. }

  414. /* -- Lexer API ----------------------------------------------------------- */

  415. /* Setup lexer state. */
  416. int kp_lex_setup(LexState *ls, const char *str)
  417. {
  418.     ls->fs = NULL;
  419.     ls->pe = ls->p = NULL;
  420.     ls->p = str;
  421.     ls->pe = str + strlen(str);
  422.     ls->vstack = NULL;
  423.     ls->sizevstack = 0;
  424.     ls->vtop = 0;
  425.     ls->bcstack = NULL;
  426.     ls->sizebcstack = 0;
  427.     ls->lookahead = TK_eof;  /* No look-ahead token. */
  428.     ls->linenumber = 1;
  429.     ls->lastline = 1;
  430.     lex_next(ls);  /* Read-ahead first char. */
  431.     if (ls->c == 0xef && ls->p + 2 <= ls->pe &&
  432.         (uint8_t)ls->p[0] == 0xbb &&
  433.         (uint8_t)ls->p[1] == 0xbf) {/* Skip UTF-8 BOM (if buffered). */
  434.         ls->p += 2;
  435.         lex_next(ls);
  436.     }
  437.     if (ls->c == '#') {  /* Skip POSIX #! header line. */
  438.         do {
  439.             lex_next(ls);
  440.             if (ls->c == LEX_EOF)
  441.                 return 0;
  442.         } while (!lex_iseol(ls));
  443.         lex_newline(ls);
  444.     }
  445.     return 0;
  446. }

  447. /* Cleanup lexer state. */
  448. void kp_lex_cleanup(LexState *ls)
  449. {
  450.     free(ls->bcstack);
  451.     free(ls->vstack);
  452.     kp_buf_free(&ls->sb);
  453. }

  454. /* Return next lexical token. */
  455. void kp_lex_next(LexState *ls)
  456. {
  457.     ls->lastline = ls->linenumber;
  458.     if (ls->lookahead == TK_eof) {  /* No lookahead token? */
  459.         ls->tok = lex_scan(ls, &ls->tokval);  /* Get next token. */
  460.     } else/* Otherwise return lookahead token. */
  461.         ls->tok = ls->lookahead;
  462.         ls->lookahead = TK_eof;
  463.         ls->tokval = ls->lookaheadval;
  464.     }
  465. }

  466. /* Look ahead for the next token. */
  467. LexToken kp_lex_lookahead(LexState *ls)
  468. {
  469.     kp_assert(ls->lookahead == TK_eof);
  470.     ls->lookahead = lex_scan(ls, &ls->lookaheadval);
  471.     return ls->lookahead;
  472. }

  473. /* Convert token to string. */
  474. const char *kp_lex_token2str(LexState *ls, LexToken tok)
  475. {
  476.     if (tok > TK_OFS)
  477.         return tokennames[tok-TK_OFS-1];
  478.     else if (!kp_char_iscntrl(tok))
  479.         return kp_sprintf("%c", tok);
  480.     else
  481.         return kp_sprintf("char(%d)", tok);
  482. }

  483. /* Lexer error. */
  484. void kp_lex_error(LexState *ls, LexToken tok, ErrMsg em, ...)
  485. {
  486.     const char *tokstr;
  487.     va_list argp;

  488.     if (tok == 0) {
  489.         tokstr = NULL;
  490.     } else if (tok == TK_name || tok == TK_string || tok == TK_number) {
  491.         lex_save(ls, '\0');
  492.         tokstr = sbufB(&ls->sb);
  493.     } else {
  494.         tokstr = kp_lex_token2str(ls, tok);
  495.     }

  496.     va_start(argp, em);
  497.     kp_err_lex(ls->chunkname, tokstr, ls->linenumber, em, argp);
  498.     va_end(argp);
  499. }

  500. /* Initialize strings for reserved words. */
  501. void kp_lex_init()
  502. {
  503.     uint32_t i;

  504.     for (i = 0; i < TK_RESERVED; i++) {
  505.         ktap_str_t *s = kp_str_newz(tokennames[i]);
  506.         s->reserved = (uint8_t)(i+1);
  507.     }
  508. }