parser: use "atom" instead of "sval" in yylval
[platform/upstream/libxkbcommon.git] / src / xkbcomp / scanner.c
1 /*
2  * Copyright © 2012 Ran Benita <ran234@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         while (!eof(s) && !eol(s)) next(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);
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 }