1 /*
2 * Motif Tools Library, Version 3.1
3 * $Id: Lexer.c,v 1.3 2001/09/19 02:57:18 grmcdorman Exp $
4 *
5 * Written by David Flanagan.
6 * Copyright (c) 1992-2001 by David Flanagan.
7 * All Rights Reserved. See the file COPYRIGHT for details.
8 * This is open source software. See the file LICENSE for details.
9 * There is no warranty for this software. See NO_WARRANTY for details.
10 *
11 * $Log: Lexer.c,v $
12 * Revision 1.3 2001/09/19 02:57:18 grmcdorman
13 * This change makes the following modifications:
14 * A new program, printConfig, is provided. This is built by a
15 * simple rule in the Makefile and not installed. It prints
16 * significant defines from Xmt.tmpl.
17 *
18 * XmtP.h is now generated from XmtP.h.in using printConfig. As
19 * a result, code compiled outside of the Xmt Imakefiles will
20 * have all of the Xmt.tmpl defines.
21 *
22 * Source files are modified to use XmtP.h instead of Xmt.h.
23 *
24 * WorkingBox.c is modified to use the new Progress widget.
25 * It can be compiled in the old style if WORKINGBOX_USE_SCALE is
26 * defined at compile time.
27 *
28 * Because XmtP.h is generated dynamically, it is removed from CVS
29 * with this check-in.
30 *
31 * Revision 1.2 2001/05/17 03:58:07 motiftools
32 * Added patch to lexer for handling c++ class::method() scoping rules if
33 * enabled with XMT_HAS_XMTPP flag. Credit goes to the authors of Xmt++ for
34 * lexer code -- Bin Mu and Harry Danilevsky.
35 *
36 * Revision 1.1.1.1 2001/02/10 13:47:18 motiftools
37 * Initial import of Xmt310 to CVS
38 *
39 *
40 */
41
42 #include <ctype.h>
43 #include <Xmt/XmtP.h>
44 #include <Xmt/Lexer.h>
45
46 #if NeedFunctionPrototypes
XmtLexerCreate(String * keywords,int num_keywords)47 XmtLexer XmtLexerCreate(String *keywords, int num_keywords)
48 #else
49 XmtLexer XmtLexerCreate(keywords, num_keywords)
50 String *keywords;
51 int num_keywords;
52 #endif
53 {
54 XmtLexer lexer = XtNew(XmtLexerRec);
55
56 lexer->c = NULL;
57 lexer->token = XmtLexerNone;
58 lexer->intval = 0;
59 lexer->strval = NULL;
60 lexer->keywords = keywords;
61 lexer->num_keywords = num_keywords;
62 return lexer;
63 }
64
65 #if NeedFunctionPrototypes
XmtLexerDestroy(XmtLexer lexer)66 void XmtLexerDestroy(XmtLexer lexer)
67 #else
68 void XmtLexerDestroy(lexer)
69 XmtLexer lexer;
70 #endif
71 {
72 XtFree((char *)lexer);
73 }
74
75 #if NeedFunctionPrototypes
XmtLexerInit(XmtLexer lexer,StringConst str)76 void XmtLexerInit(XmtLexer lexer, StringConst str)
77 #else
78 void XmtLexerInit(lexer, str)
79 XmtLexer lexer;
80 StringConst str;
81 #endif
82 {
83 lexer->c = str;
84 lexer->token = XmtLexerNone;
85 lexer->intval = 0;
86 lexer->strval = NULL;
87 }
88
89 #if NeedFunctionPrototypes
_XmtLexerGetToken(XmtLexer l)90 XmtLexerToken _XmtLexerGetToken(XmtLexer l)
91 #else
92 XmtLexerToken _XmtLexerGetToken(l)
93 XmtLexer l;
94 #endif
95 {
96 int total;
97 int len;
98 _Xconst char *mark;
99 int keyword;
100
101 l->token = XmtLexerNone;
102
103 if (l->c == NULL) {
104 l->token = XmtLexerEndOfString;
105 return l->token;
106 }
107
108 /* skip whitespace */
109 while (isspace((int)*l->c)) l->c++;
110
111 /* check for end-of-string */
112 if (*l->c == '\0') {
113 l->token = XmtLexerEndOfString;
114 return l->token;
115 }
116
117 /* check punctuation */
118 switch (*l->c) {
119 case '(': l->token = XmtLexerLParen; break;
120 case ')': l->token = XmtLexerRParen; break;
121 case '[': l->token = XmtLexerLBracket; break;
122 case ']': l->token = XmtLexerRBracket; break;
123 case '{': l->token = XmtLexerLBrace; break;
124 case '}': l->token = XmtLexerRBrace; break;
125 case '<': l->token = XmtLexerLess; break;
126 case '>': l->token = XmtLexerGreater; break;
127 case '+': l->token = XmtLexerPlus; break;
128 case '-': l->token = XmtLexerMinus; break;
129 case '*': l->token = XmtLexerAsterisk; break;
130 case '/': l->token = XmtLexerSlash; break;
131 case '|': l->token = XmtLexerBar; break;
132 case '=': l->token = XmtLexerEqual; break;
133 case '#': l->token = XmtLexerSharp; break;
134 case '~': l->token = XmtLexerTwiddle; break;
135 case '%': l->token = XmtLexerPercent; break;
136 case '$': l->token = XmtLexerDollar; break;
137 case '.': l->token = XmtLexerPeriod; break;
138 case '^': l->token = XmtLexerCaret; break;
139 case ':': l->token = XmtLexerColon; break;
140 case ';': l->token = XmtLexerSemicolon; break;
141 case ',': l->token = XmtLexerComma; break;
142 }
143
144 if (l->token != XmtLexerNone) {
145 #ifdef XMT_HAS_XMTPP
146 if (!(l->token != XmtLexerNone) ||
147 !(*(l->c+1) == ':')) {
148 l->c++;
149 }
150 #else
151 l->c++;
152 #endif
153 return l->token;
154 }
155
156 if (isdigit((int)*l->c)) {
157 total = 0;
158 while (isdigit((int)*l->c)) {
159 total *= 10;
160 total += (int)(*l->c - '0');
161 l->c++;
162 }
163 l->token = XmtLexerInteger;
164 l->intval = total;
165 }
166 else if (*l->c == '"') { /* its a string */
167 l->c++;
168 mark = l->c;
169 while((*l->c != '\0') && (*l->c != '"')) {
170 if ((*l->c == '\\') && (*(l->c+1) != '\0'))
171 l->c++;
172 l->c++;
173 }
174 if (*l->c == '\0') {
175 XmtWarningMsg("XmtLexer", "badString",
176 "unterminated string.");
177 l->token = XmtLexerError;
178 }
179 else {
180 len = l->c - mark;
181 l->c++;
182 l->strval = XtMalloc(len+1);
183 strncpy(l->strval, mark, len);
184 l->strval[len] = '\0';
185 l->intval = len;
186 l->token = XmtLexerString;
187 }
188 }
189 else if (isalnum(*l->c) || (*l->c == '_')) {
190 /* its an ident. Figure out how long and copy it. */
191 mark = l->c;
192 #ifdef XMT_HAS_XMTPP
193 for(len=0; *l->c; len++, l->c++) {
194 if (isalnum((int)*l->c) || (*l->c == '_')) {
195 continue;
196 } else if ((*l->c == ':') && ( *(l->c+1) == ':')) {
197 len++;
198 l->c++;
199 }
200 else break;
201 }
202 #else
203 for(len=0; *l->c &&
204 (isalnum((int)*l->c) || (*l->c == '_'));
205 len++,l->c++);
206 #endif
207 l->strval = XtMalloc(len+1);
208 strncpy(l->strval, mark, len);
209 l->strval[len] = '\0';
210 l->intval = len;
211
212 /* now go see if it is a keyword. */
213 keyword = XmtBSearch(l->strval, l->keywords, l->num_keywords);
214
215 if (keyword != -1) {
216 l->intval = keyword;
217 l->token = XmtLexerKeyword;
218 XtFree(l->strval);
219 l->strval = l->keywords[keyword];
220 }
221 else
222 l->token = XmtLexerIdent;
223 }
224 else { /* otherwise it is an unrecognized character. */
225 XmtWarningMsg("XmtLexer", "badChar",
226 "unrecognized character `%c'.",
227 *l->c);
228 l->c++;
229 l->token = XmtLexerError;
230 }
231
232 return l->token;
233 }
234
235 /*
236 * Scan from the current lexer location until an unquoted character
237 * from the delimiters string is encountered. Copy the string and return
238 * XmtLexerString. If include is True, include the delimiter, otherwise
239 * don't. If the end of string is found return XmtLexerEndOfString.
240 */
241
242 #if NeedFunctionPrototypes
XmtLexerScan(XmtLexer l,StringConst delimiters,XmtWideBoolean include)243 XmtLexerToken XmtLexerScan(XmtLexer l, StringConst delimiters,
244 XmtWideBoolean include)
245 #else
246 XmtLexerToken XmtLexerScan(l, delimiters, include)
247 XmtLexer l;
248 StringConst delimiters;
249 int include;
250 #endif
251 {
252 _Xconst char *c, *d;
253 Boolean instring = False;
254
255 if (l->c == '\0') {
256 l->token = XmtLexerEndOfString;
257 return XmtLexerEndOfString;
258 }
259
260 for(c = l->c; *c; c++) {
261 if (!instring) {
262 for(d = delimiters; *d && (*d != *c); d++);
263 if (*d) break;
264 }
265 if ((*c == '\\') && *(c+1)) c++;
266 else if (*c == '"') instring = !instring;
267 }
268
269 if (*c == '\0') {
270 l->c = c;
271 l->token = XmtLexerEndOfString;
272 return XmtLexerEndOfString;
273 }
274
275 /*
276 * if include is True, we include the terminating delimiter.
277 */
278 if (include) c++;
279
280 l->intval = c - l->c;
281 l->strval = XtMalloc(l->intval +1);
282 strncpy(l->strval, l->c, l->intval);
283 l->strval[l->intval] = '\0';
284 l->c = c;
285 l->token = XmtLexerString;
286 return XmtLexerString;
287 }
288
289 #if NeedFunctionPrototypes
GetArg(XmtLexer l)290 static String GetArg(XmtLexer l)
291 #else
292 static String GetArg(l)
293 XmtLexer l;
294 #endif
295 {
296 _Xconst char *c, *s;
297 register char *t;
298 Boolean instring;
299 int parenlevel;
300 int len;
301 char *arg;
302
303 /*
304 * This procedure breaks the XmtLexer abstraction and scans the
305 * string directly. It should only be called when the last token
306 * has been consumed.
307 */
308
309 /* skip whitespace */
310 XmtLexerSkipWhite(l);
311
312 /* special case for procedures with 0 args */
313 if (*l->c == ')') {
314 return NULL;
315 }
316
317 /* scan to an unquoted, unnested comma or right paren */
318 instring = False;
319 parenlevel = 0;
320 for(c = l->c; *c; c++) {
321 if (*c == '\0') break;
322 else if (!instring && parenlevel<=0 && (*c == ',' || *c == ')')) break;
323 else if (*c == '"') instring = !instring;
324 else if (!instring && *c == '(') parenlevel++;
325 else if (!instring && *c == ')') parenlevel--;
326 else if ((*c == '\\') && (*(c+1) != '\0')) c++;
327 }
328
329 /* back up over any whitespace */
330 while(isspace(*(c-1))) c--;
331
332 /* allocate space for a copy of the arg */
333 len = (int) (c - l->c);
334 arg = XtMalloc(len+1);
335
336 /* copy it, unquoting things */
337 for(s = l->c, t = arg; s < c; s++) {
338 if (*s == '\\') *t++ = *++s;
339 else *t++ = *s;
340 }
341
342 /* and terminate the string */
343 *t = '\0';
344
345 /* put the lexer back in a known state */
346 l->c = c;
347 l->token = XmtLexerNone;
348
349 return arg;
350 }
351
352 #if NeedFunctionPrototypes
XmtLexerGetArgList(XmtLexer l,String * args,Cardinal max_args,Cardinal * num_args)353 Boolean XmtLexerGetArgList(XmtLexer l, String *args,
354 Cardinal max_args, Cardinal *num_args)
355 #else
356 Boolean XmtLexerGetArgList(l, args, max_args, num_args)
357 XmtLexer l;
358 String *args;
359 Cardinal max_args;
360 Cardinal *num_args;
361 #endif
362 {
363 XmtLexerToken tok;
364
365 /* if no '(', then no arguments, but this is not an error. */
366 if (XmtLexerGetToken(l) != XmtLexerLParen) {
367 *num_args = 0;
368 return True;
369 }
370
371 /* otherwise eat the lparen */
372 XmtLexerConsumeToken(l);
373
374 /* now loop through the arguments */
375 *num_args = 0;
376 while(1) {
377 /* make sure we haven't overflowed */
378 if (*num_args >= max_args) {
379 XmtWarningMsg("_XmtParseArgList", "tooMany",
380 "too many arguments in argument list.");
381 goto error;
382 }
383
384 /* get the next argument */
385 args[*num_args] = GetArg(l);
386 if (args[*num_args]) *num_args += 1;
387
388 /* consume a comma or a right paren */
389 tok = XmtLexerGetToken(l);
390 if (tok == XmtLexerRParen) {
391 XmtLexerConsumeToken(l);
392 return True;
393 }
394 else if (tok == XmtLexerComma)
395 XmtLexerConsumeToken(l);
396 else {
397 XmtWarningMsg("_XmtParseArgList", "syntax",
398 "syntax error in argument list");
399 goto error;
400 }
401 }
402
403 error:
404 /* read past closing ')' */
405 while(((tok = XmtLexerGetToken(l)) != XmtLexerEndOfString) &&
406 (tok != XmtLexerRParen))
407 XmtLexerConsumeToken(l);
408 XmtLexerConsumeToken(l);
409 return False;
410 }
411