Contiki-NG
aql-lexer.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, Swedish Institute of Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /**
31  * \file
32  * Lexical analyzer for AQL, the Antelope Query Language.
33  * \author
34  * Nicolas Tsiftes <nvt@sics.se>
35  */
36 
37 #include "aql.h"
38 
39 #include <ctype.h>
40 #include <errno.h>
41 #include <limits.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <strings.h>
46 
47 struct keyword {
48  char *string;
49  token_t token;
50 };
51 
52 /* The keywords are arranged primarily by length and
53  secondarily by expected lookup frequency. */
54 static const struct keyword keywords[] = {
55  {";", END},
56  {"(", LEFT_PAREN},
57  {")", RIGHT_PAREN},
58  {",", COMMA},
59  {"=", EQUAL},
60  {">", GT},
61  {"<", LT},
62  {".", DOT},
63  {"+", ADD},
64  {"-", SUB},
65  {"*", MUL},
66  {"/", DIV},
67  {"#", COMMENT},
68 
69  {">=", GEQ},
70  {"<=", LEQ},
71  {"<>", NOT_EQUAL},
72  {"<-", ASSIGN},
73  {"OR", OR},
74  {"IS", IS},
75  {"ON", ON},
76  {"IN", IN},
77 
78  {"AND", AND},
79  {"NOT", NOT},
80  {"SUM", SUM},
81  {"MAX", MAX},
82  {"MIN", MIN},
83  {"INT", INT},
84 
85  {"INTO", INTO},
86  {"FROM", FROM},
87  {"MEAN", MEAN},
88  {"JOIN", JOIN},
89  {"LONG", LONG},
90  {"TYPE", TYPE},
91 
92  {"WHERE", WHERE},
93  {"COUNT", COUNT},
94  {"INDEX", INDEX},
95 
96  {"INSERT", INSERT},
97  {"SELECT", SELECT},
98  {"REMOVE", REMOVE},
99  {"CREATE", CREATE},
100  {"MEDIAN", MEDIAN},
101  {"DOMAIN", DOMAIN},
102  {"STRING", STRING},
103  {"INLINE", INLINE},
104 
105  {"PROJECT", PROJECT},
106  {"MAXHEAP", MAXHEAP},
107  {"MEMHASH", MEMHASH},
108 
109  {"RELATION", RELATION},
110 
111  {"ATTRIBUTE", ATTRIBUTE}
112 };
113 
114 /* Provides a pointer to the first keyword of a specific length. */
115 static const int8_t skip_hint[] = {0, 13, 21, 27, 33, 36, 44, 47, 48};
116 
117 static char separators[] = "#.;,() \t\n";
118 
119 int
120 lexer_start(lexer_t *lexer, char *input, token_t *token, value_t *value)
121 {
122  lexer->input = input;
123  lexer->prev_pos = input;
124  lexer->token = token;
125  lexer->value = value;
126 
127  return 0;
128 }
129 
130 static token_t
131 get_token_id(const char *string, const size_t length)
132 {
133  int start, end;
134  int i;
135 
136  if(sizeof(skip_hint) < length || length < 1) {
137  return NONE;
138  }
139 
140 
141  start = skip_hint[length - 1];
142  if(sizeof(skip_hint) == length) {
143  end = sizeof(keywords) / sizeof(keywords[0]);
144  } else {
145  end = skip_hint[length];
146  }
147 
148  for(i = start; i < end; i++) {
149  if(strncasecmp(keywords[i].string, string, length) == 0) {
150  return keywords[i].token;
151  }
152  }
153 
154  return NONE;
155 }
156 
157 static int
158 next_real(lexer_t *lexer, const char *s)
159 {
160  char *end;
161  long long_value;
162 #if DB_FEATURE_FLOATS
163  float float_value;
164 #endif /* DB_FEATURE_FLOATS */
165 
166  errno = 0;
167  long_value = strtol(s, &end, 10);
168 
169 #if DB_FEATURE_FLOATS
170  if(*end == '.') {
171  /* Process a float value. */
172  float_value = strtof(s, &end);
173  if(float_value == 0 && s == end) {
174  return -1;
175  }
176  memcpy(lexer->value, &float_value, sizeof(float_value));
177  *lexer->token = FLOAT_VALUE;
178  lexer->input = end;
179 
180  return 1;
181  }
182 #endif /* DB_FEATURE_FLOATS */
183 
184  /* Process an integer value. */
185  if(long_value == 0 && errno != 0) {
186  return -1;
187  }
188  memcpy(lexer->value, &long_value, sizeof(long_value));
189  *lexer->token = INTEGER_VALUE;
190  lexer->input = end;
191 
192  return 1;
193 }
194 
195 static int
196 next_string(lexer_t *lexer, const char *s)
197 {
198  char *end;
199  size_t length;
200 
201  end = strchr(s, '\'');
202  if(end == NULL) {
203  return -1;
204  }
205 
206  length = end - s;
207  *lexer->token = STRING_VALUE;
208  lexer->input = end + 1; /* Skip the closing delimiter. */
209 
210  if(length > DB_MAX_ELEMENT_SIZE - 1) {
211  length = DB_MAX_ELEMENT_SIZE - 1;
212  }
213 
214  memcpy(lexer->value, s, length);
215  (*lexer->value)[length] = '\0';
216 
217  return 1;
218 }
219 
220 static int
221 next_token(lexer_t *lexer, const char *s)
222 {
223  size_t length;
224 
225  length = strcspn(s, separators);
226  if(length == 0) {
227  /* We encountered a separator, so we try to get a token of
228  precisely 1 byte. */
229  length = 1;
230  }
231 
232  *lexer->token = get_token_id(s, length);
233  lexer->input = s + length;
234  if(*lexer->token != NONE) {
235  return 1;
236  }
237 
238  /* The input did not constitute a valid token,
239  so we regard it as an identifier. */
240 
241  *lexer->token = IDENTIFIER;
242 
243  if(length > DB_MAX_ELEMENT_SIZE - 1) {
244  length = DB_MAX_ELEMENT_SIZE - 1;
245  }
246 
247  memcpy(lexer->value, s, length);
248  (*lexer->value)[length] = '\0';
249 
250  return 1;
251 }
252 
253 int
254 lexer_next(lexer_t *lexer)
255 {
256  const char *s;
257 
258  *lexer->token = NONE;
259  s = lexer->input;
260  s += strspn(s, " \t\n");
261  lexer->prev_pos = s;
262 
263  switch(*s) {
264  case '\'':
265  /* Process the string that follows the delimiter. */
266  return next_string(lexer, s + 1);
267  case '\0':
268  return 0;
269  default:
270  if(isdigit((int)*s) || (*s == '-' && isdigit((int)s[1]))) {
271  return next_real(lexer, s);
272  }
273 
274  /* Process a token. */
275  return next_token(lexer, s);
276  }
277 }
278 
279 void
280 lexer_rewind(lexer_t *lexer)
281 {
282  lexer->input = lexer->prev_pos;
283 }
static bool start(void)
Start measurement.
Definitions and declarations for AQL, the Antelope Query Language.
static void input(void)
Process a received 6lowpan packet.
Definition: sicslowpan.c:1777