Edit

kc3-lang/libxkbcommon/src/xkbcomp/scanner.c

Branch :

  • Show log

    Commit

  • Author : Ran Benita
    Date : 2015-11-19 00:44:27
    Hash : 2cca0289
    Message : src/utils: change map_file to not take const string argument map_file() uses PROT_READ, so const seems fitting; however unmap_file calls munmap/free, which do not take const, so an UNCONSTIFY is needed. To avoid the UNCONSTIFY hack, which is likely undefined behavior or some such, just remove the const. Signed-off-by: Ran Benita <ran234@gmail.com>

  • src/xkbcomp/scanner.c
  • /*
     * Copyright © 2012 Ran Benita <ran234@gmail.com>
     *
     * Permission is hereby granted, free of charge, to any person obtaining a
     * copy of this software and associated documentation files (the "Software"),
     * to deal in the Software without restriction, including without limitation
     * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     * and/or sell copies of the Software, and to permit persons to whom the
     * Software is furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice (including the next
     * paragraph) shall be included in all copies or substantial portions of the
     * Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     * DEALINGS IN THE SOFTWARE.
     */
    
    #include "xkbcomp-priv.h"
    #include "parser-priv.h"
    #include "scanner-utils.h"
    
    static bool
    number(struct scanner *s, int64_t *out, int *out_tok)
    {
        bool is_float = false, is_hex = false;
        const char *start = s->s + s->pos;
        char *end;
    
        if (lit(s, "0x")) {
            while (is_xdigit(peek(s))) next(s);
            is_hex = true;
        }
        else {
            while (is_digit(peek(s))) next(s);
            is_float = chr(s, '.');
            while (is_digit(peek(s))) next(s);
        }
        if (s->s + s->pos == start)
            return false;
    
        errno = 0;
        if (is_hex)
            *out = strtoul(start, &end, 16);
        else if (is_float)
            *out = strtod(start, &end);
        else
            *out = strtoul(start, &end, 10);
        if (errno != 0 || s->s + s->pos != end)
            *out_tok = ERROR_TOK;
        else
            *out_tok = (is_float ? FLOAT : INTEGER);
        return true;
    }
    
    int
    _xkbcommon_lex(YYSTYPE *yylval, struct scanner *s)
    {
        int tok;
    
    skip_more_whitespace_and_comments:
        /* Skip spaces. */
        while (is_space(peek(s))) next(s);
    
        /* Skip comments. */
        if (lit(s, "//") || chr(s, '#')) {
            skip_to_eol(s);
            goto skip_more_whitespace_and_comments;
        }
    
        /* See if we're done. */
        if (eof(s)) return END_OF_FILE;
    
        /* New token. */
        s->token_line = s->line;
        s->token_column = s->column;
        s->buf_pos = 0;
    
        /* String literal. */
        if (chr(s, '\"')) {
            while (!eof(s) && !eol(s) && peek(s) != '\"') {
                if (chr(s, '\\')) {
                    uint8_t o;
                    if      (chr(s, '\\')) buf_append(s, '\\');
                    else if (chr(s, 'n'))  buf_append(s, '\n');
                    else if (chr(s, 't'))  buf_append(s, '\t');
                    else if (chr(s, 'r'))  buf_append(s, '\r');
                    else if (chr(s, 'b'))  buf_append(s, '\b');
                    else if (chr(s, 'f'))  buf_append(s, '\f');
                    else if (chr(s, 'v'))  buf_append(s, '\v');
                    else if (chr(s, 'e'))  buf_append(s, '\033');
                    else if (oct(s, &o))   buf_append(s, (char) o);
                    else {
                        scanner_warn(s, "unknown escape sequence in string literal");
                        /* Ignore. */
                    }
                } else {
                    buf_append(s, next(s));
                }
            }
            if (!buf_append(s, '\0') || !chr(s, '\"')) {
                scanner_err(s, "unterminated string literal");
                return ERROR_TOK;
            }
            yylval->str = strdup(s->buf);
            if (!yylval->str)
                return ERROR_TOK;
            return STRING;
        }
    
        /* Key name literal. */
        if (chr(s, '<')) {
            while (is_graph(peek(s)) && peek(s) != '>')
                buf_append(s, next(s));
            if (!buf_append(s, '\0') || !chr(s, '>')) {
                scanner_err(s, "unterminated key name literal");
                return ERROR_TOK;
            }
            /* Empty key name literals are allowed. */
            yylval->atom = xkb_atom_intern(s->ctx, s->buf, s->buf_pos - 1);
            return KEYNAME;
        }
    
        /* Operators and punctuation. */
        if (chr(s, ';')) return SEMI;
        if (chr(s, '{')) return OBRACE;
        if (chr(s, '}')) return CBRACE;
        if (chr(s, '=')) return EQUALS;
        if (chr(s, '[')) return OBRACKET;
        if (chr(s, ']')) return CBRACKET;
        if (chr(s, '(')) return OPAREN;
        if (chr(s, ')')) return CPAREN;
        if (chr(s, '.')) return DOT;
        if (chr(s, ',')) return COMMA;
        if (chr(s, '+')) return PLUS;
        if (chr(s, '-')) return MINUS;
        if (chr(s, '*')) return TIMES;
        if (chr(s, '/')) return DIVIDE;
        if (chr(s, '!')) return EXCLAM;
        if (chr(s, '~')) return INVERT;
    
        /* Identifier. */
        if (is_alpha(peek(s)) || peek(s) == '_') {
            s->buf_pos = 0;
            while (is_alnum(peek(s)) || peek(s) == '_')
                buf_append(s, next(s));
            if (!buf_append(s, '\0')) {
                scanner_err(s, "identifier too long");
                return ERROR_TOK;
            }
    
            /* Keyword. */
            tok = keyword_to_token(s->buf, s->buf_pos - 1);
            if (tok != -1) return tok;
    
            yylval->str = strdup(s->buf);
            if (!yylval->str)
                return ERROR_TOK;
            return IDENT;
        }
    
        /* Number literal (hexadecimal / decimal / float). */
        if (number(s, &yylval->num, &tok)) {
            if (tok == ERROR_TOK) {
                scanner_err(s, "malformed number literal");
                return ERROR_TOK;
            }
            return tok;
        }
    
        scanner_err(s, "unrecognized token");
        return ERROR_TOK;
    }
    
    XkbFile *
    XkbParseString(struct xkb_context *ctx, const char *string, size_t len,
                   const char *file_name, const char *map)
    {
        struct scanner scanner;
        scanner_init(&scanner, ctx, string, len, file_name, NULL);
        return parse(ctx, &scanner, map);
    }
    
    XkbFile *
    XkbParseFile(struct xkb_context *ctx, FILE *file,
                 const char *file_name, const char *map)
    {
        bool ok;
        XkbFile *xkb_file;
        char *string;
        size_t size;
    
        ok = map_file(file, &string, &size);
        if (!ok) {
            log_err(ctx, "Couldn't read XKB file %s: %s\n",
                    file_name, strerror(errno));
            return NULL;
        }
    
        xkb_file = XkbParseString(ctx, string, size, file_name, map);
        unmap_file(string, size);
        return xkb_file;
    }