diff options
Diffstat (limited to 'src/xkbcomp/scanner.c')
-rw-r--r-- | src/xkbcomp/scanner.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/src/xkbcomp/scanner.c b/src/xkbcomp/scanner.c new file mode 100644 index 0000000..4be2c40 --- /dev/null +++ b/src/xkbcomp/scanner.c @@ -0,0 +1,205 @@ +/* + * 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" + +int +scanner_error(YYLTYPE *yylloc, struct scanner *s, const char *msg) +{ + log_err(s->ctx, "%s:%d:%d: %s\n", + s->file_name, yylloc->first_line, yylloc->first_column, msg); + return ERROR_TOK; +} + +static bool +number(struct scanner *s, int64_t *out, enum yytokentype *out_tok) +{ + bool is_float = false, is_hex = false; + const char *start = s->s + s->pos; + char *end; + + if (lit(s, "0x")) { + while (isxdigit(peek(s))) next(s); + is_hex = true; + } + else { + while (isdigit(peek(s))) next(s); + is_float = chr(s, '.'); + while (isdigit(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, YYLTYPE *yylloc, struct scanner *s) +{ + enum yytokentype tok; + +skip_more_whitespace_and_comments: + /* Skip spaces. */ + while (isspace(peek(s))) next(s); + + /* Skip comments. */ + if (lit(s, "//") || chr(s, '#')) { + while (!eof(s) && !eol(s)) next(s); + goto skip_more_whitespace_and_comments; + } + + /* See if we're done. */ + if (eof(s)) return END_OF_FILE; + + /* New token. */ + yylloc->first_line = yylloc->last_line = s->line; + yylloc->first_column = yylloc->last_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 return scanner_error(yylloc, s, + "illegal escape sequence in string literal"); + } else { + buf_append(s, next(s)); + } + } + if (!buf_append(s, '\0') || !chr(s, '\"')) + return scanner_error(yylloc, s, "unterminated string literal"); + yylval->str = strdup(s->buf); + if (!yylval->str) + return scanner_error(yylloc, s, "scanner out of memory"); + return STRING; + } + + /* Key name literal. */ + if (chr(s, '<')) { + while (isgraph(peek(s)) && peek(s) != '>') + buf_append(s, next(s)); + if (s->buf_pos == 0) + return scanner_error(yylloc, s, "empty key name literal"); + if (!buf_append(s, '\0') || !chr(s, '>')) + return scanner_error(yylloc, s, "unterminated key name literal"); + yylval->sval = xkb_atom_intern(s->ctx, s->buf); + 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 EXCLAM; + if (chr(s, '~')) return INVERT; + + /* Identifier. */ + if (isalpha(peek(s)) || peek(s) == '_') { + s->buf_pos = 0; + while (isalnum(peek(s)) || peek(s) == '_') + buf_append(s, next(s)); + if (!buf_append(s, '\0')) + return scanner_error(yylloc, s, "identifier too long"); + + /* Keyword. */ + tok = keyword_to_token(s->buf); + if (tok != -1) return tok; + + yylval->str = strdup(s->buf); + if (!yylval->str) + return scanner_error(yylloc, s, "scanner out of memory"); + return IDENT; + } + + /* Number literal (hexadecimal / decimal / float). */ + if (number(s, &yylval->num, &tok)) { + if (tok == ERROR_TOK) + return scanner_error(yylloc, s, "malformed number literal"); + return tok; + } + + return scanner_error(yylloc, s, "unrecognized token"); +} + +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); + 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; + const 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; +} |