Home | History | Annotate | Download | only in xkbcomp
      1 /*
      2  * Copyright  2012 Ran Benita <ran234 (at) gmail.com>
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21  * DEALINGS IN THE SOFTWARE.
     22  */
     23 
     24 #include "xkbcomp-priv.h"
     25 #include "parser-priv.h"
     26 #include "scanner-utils.h"
     27 
     28 static bool
     29 number(struct scanner *s, int64_t *out, int *out_tok)
     30 {
     31     bool is_float = false, is_hex = false;
     32     const char *start = s->s + s->pos;
     33     char *end;
     34 
     35     if (lit(s, "0x")) {
     36         while (is_xdigit(peek(s))) next(s);
     37         is_hex = true;
     38     }
     39     else {
     40         while (is_digit(peek(s))) next(s);
     41         is_float = chr(s, '.');
     42         while (is_digit(peek(s))) next(s);
     43     }
     44     if (s->s + s->pos == start)
     45         return false;
     46 
     47     errno = 0;
     48     if (is_hex)
     49         *out = strtoul(start, &end, 16);
     50     else if (is_float)
     51         *out = strtod(start, &end);
     52     else
     53         *out = strtoul(start, &end, 10);
     54     if (errno != 0 || s->s + s->pos != end)
     55         *out_tok = ERROR_TOK;
     56     else
     57         *out_tok = (is_float ? FLOAT : INTEGER);
     58     return true;
     59 }
     60 
     61 int
     62 _xkbcommon_lex(YYSTYPE *yylval, struct scanner *s)
     63 {
     64     int tok;
     65 
     66 skip_more_whitespace_and_comments:
     67     /* Skip spaces. */
     68     while (is_space(peek(s))) next(s);
     69 
     70     /* Skip comments. */
     71     if (lit(s, "//") || chr(s, '#')) {
     72         skip_to_eol(s);
     73         goto skip_more_whitespace_and_comments;
     74     }
     75 
     76     /* See if we're done. */
     77     if (eof(s)) return END_OF_FILE;
     78 
     79     /* New token. */
     80     s->token_line = s->line;
     81     s->token_column = s->column;
     82     s->buf_pos = 0;
     83 
     84     /* String literal. */
     85     if (chr(s, '\"')) {
     86         while (!eof(s) && !eol(s) && peek(s) != '\"') {
     87             if (chr(s, '\\')) {
     88                 uint8_t o;
     89                 if      (chr(s, '\\')) buf_append(s, '\\');
     90                 else if (chr(s, 'n'))  buf_append(s, '\n');
     91                 else if (chr(s, 't'))  buf_append(s, '\t');
     92                 else if (chr(s, 'r'))  buf_append(s, '\r');
     93                 else if (chr(s, 'b'))  buf_append(s, '\b');
     94                 else if (chr(s, 'f'))  buf_append(s, '\f');
     95                 else if (chr(s, 'v'))  buf_append(s, '\v');
     96                 else if (chr(s, 'e'))  buf_append(s, '\033');
     97                 else if (oct(s, &o))   buf_append(s, (char) o);
     98                 else {
     99                     scanner_warn(s, "unknown escape sequence in string literal");
    100                     /* Ignore. */
    101                 }
    102             } else {
    103                 buf_append(s, next(s));
    104             }
    105         }
    106         if (!buf_append(s, '\0') || !chr(s, '\"')) {
    107             scanner_err(s, "unterminated string literal");
    108             return ERROR_TOK;
    109         }
    110         yylval->str = strdup(s->buf);
    111         if (!yylval->str)
    112             return ERROR_TOK;
    113         return STRING;
    114     }
    115 
    116     /* Key name literal. */
    117     if (chr(s, '<')) {
    118         while (is_graph(peek(s)) && peek(s) != '>')
    119             buf_append(s, next(s));
    120         if (!buf_append(s, '\0') || !chr(s, '>')) {
    121             scanner_err(s, "unterminated key name literal");
    122             return ERROR_TOK;
    123         }
    124         /* Empty key name literals are allowed. */
    125         yylval->atom = xkb_atom_intern(s->ctx, s->buf, s->buf_pos - 1);
    126         return KEYNAME;
    127     }
    128 
    129     /* Operators and punctuation. */
    130     if (chr(s, ';')) return SEMI;
    131     if (chr(s, '{')) return OBRACE;
    132     if (chr(s, '}')) return CBRACE;
    133     if (chr(s, '=')) return EQUALS;
    134     if (chr(s, '[')) return OBRACKET;
    135     if (chr(s, ']')) return CBRACKET;
    136     if (chr(s, '(')) return OPAREN;
    137     if (chr(s, ')')) return CPAREN;
    138     if (chr(s, '.')) return DOT;
    139     if (chr(s, ',')) return COMMA;
    140     if (chr(s, '+')) return PLUS;
    141     if (chr(s, '-')) return MINUS;
    142     if (chr(s, '*')) return TIMES;
    143     if (chr(s, '/')) return DIVIDE;
    144     if (chr(s, '!')) return EXCLAM;
    145     if (chr(s, '~')) return INVERT;
    146 
    147     /* Identifier. */
    148     if (is_alpha(peek(s)) || peek(s) == '_') {
    149         s->buf_pos = 0;
    150         while (is_alnum(peek(s)) || peek(s) == '_')
    151             buf_append(s, next(s));
    152         if (!buf_append(s, '\0')) {
    153             scanner_err(s, "identifier too long");
    154             return ERROR_TOK;
    155         }
    156 
    157         /* Keyword. */
    158         tok = keyword_to_token(s->buf, s->buf_pos - 1);
    159         if (tok != -1) return tok;
    160 
    161         yylval->str = strdup(s->buf);
    162         if (!yylval->str)
    163             return ERROR_TOK;
    164         return IDENT;
    165     }
    166 
    167     /* Number literal (hexadecimal / decimal / float). */
    168     if (number(s, &yylval->num, &tok)) {
    169         if (tok == ERROR_TOK) {
    170             scanner_err(s, "malformed number literal");
    171             return ERROR_TOK;
    172         }
    173         return tok;
    174     }
    175 
    176     scanner_err(s, "unrecognized token");
    177     return ERROR_TOK;
    178 }
    179 
    180 XkbFile *
    181 XkbParseString(struct xkb_context *ctx, const char *string, size_t len,
    182                const char *file_name, const char *map)
    183 {
    184     struct scanner scanner;
    185     scanner_init(&scanner, ctx, string, len, file_name, NULL);
    186     return parse(ctx, &scanner, map);
    187 }
    188 
    189 XkbFile *
    190 XkbParseFile(struct xkb_context *ctx, FILE *file,
    191              const char *file_name, const char *map)
    192 {
    193     bool ok;
    194     XkbFile *xkb_file;
    195     const char *string;
    196     size_t size;
    197 
    198     ok = map_file(file, &string, &size);
    199     if (!ok) {
    200         log_err(ctx, "Couldn't read XKB file %s: %s\n",
    201                 file_name, strerror(errno));
    202         return NULL;
    203     }
    204 
    205     xkb_file = XkbParseString(ctx, string, size, file_name, map);
    206     unmap_file(string, size);
    207     return xkb_file;
    208 }
    209