1 /**
2  *
3  * $Id: uillex.c,v 1.1 2004/08/28 19:22:42 dannybackx Exp $
4  *
5  * Copyright (C) 1995 Free Software Foundation, Inc.
6  * Copyright (C) 1995-2002 LessTif Development Team
7  *
8  * This file is part of the GNU LessTif Library.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the Free
22  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  */
25 
26 static const char rcsid[] = "$Id: uillex.c,v 1.1 2004/08/28 19:22:42 dannybackx Exp $";
27 
28 #include <LTconfig.h>
29 
30 /* Enable this for verbose lexing */
31 /* #define DEBUG */
32 
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <ctype.h>
39 #include <errno.h>
40 #ifdef HAVE_FCNTL_H
41 #include <fcntl.h>
42 #endif
43 
44 #include <XmI/UilI.h>
45 #include <uil/UilSymGl.h>
46 
47 #include <XmI/DebugUtil.h>
48 
49 
50 extern void
_uilmsg(Uil_parse_data * pd,int severity,const char * fmt,...)51 _uilmsg(Uil_parse_data *pd, int severity, const char *fmt, ...)
52 {
53     va_list arg_list;
54 
55     va_start(arg_list, fmt);
56     vfprintf(stderr, fmt, arg_list);
57     va_end(arg_list);
58 }
59 
60 
61 static unsigned char
hashval(const char * data,int len)62 hashval(const char *data, int len)
63 {
64     int i;
65     unsigned char hash = 0;
66 
67     for (i = 0; i < len; i++)
68     {
69 	hash += data[i] * i;
70     }
71 
72     hash %= sym_k_hash_table_limit;
73 
74     return hash;
75 }
76 
77 
78 static sym_entry *
add_symbol(Uil_parse_data * pd,char * data,int len,int type)79 add_symbol(Uil_parse_data *pd, char *data, int len, int type)
80 {
81     int hash = hashval(data, len);
82     sym_entry *e, **lst;
83 
84     e = (sym_entry *)XtMalloc(sizeof(sym_entry));
85 
86     for (lst = &pd->hash[hash]; *lst != NULL; lst = &(*lst)->next)
87 	;
88 
89     *lst = e;
90 
91     e->next = NULL;
92     e->type = type;
93     e->text = XtMalloc(len);
94     e->len = len;
95     memcpy(e->text, data, len);
96     e->e.entry = NULL;
97 
98     return e;
99 }
100 
101 
102 static sym_entry *
find_symbol(Uil_parse_data * pd,char * data,int len)103 find_symbol(Uil_parse_data *pd, char *data, int len)
104 {
105     int hash = hashval(data, len);
106     sym_entry *lst;
107 
108     for (lst = pd->hash[hash]; lst != NULL; lst = lst->next)
109     {
110 	if (lst->len == len && memcmp(lst->text, data, len) == 0)
111 	{
112 	    return lst;
113 	}
114     }
115 
116     return NULL;
117 }
118 
119 
120 static void
add_file(Uil_parse_data * pd,char * fn)121 add_file(Uil_parse_data *pd, char *fn)
122 {
123     int i;
124 
125     if (pd->files == NULL)
126     {
127 	pd->max_files = 10;
128 
129 	pd->files = (char **)XtCalloc(pd->max_files, sizeof(char *));
130 
131 	pd->num_files = 0;
132 
133 	pd->cur_file_name_idx = 0;
134     }
135     else if (pd->num_files == pd->max_files - 1)
136     {
137 	pd->max_files <<= 1;
138 
139 	pd->files = (char **)XtRealloc((char *)pd->files,
140 				       pd->max_files * sizeof(char *));
141     }
142 
143     for (i = 0; i < pd->num_files; i++)
144     {
145 	if (strcmp(fn, pd->files[i]) == 0)
146 	{
147 	    pd->cur_file_name_idx = i;
148 
149 	    return;
150 	}
151     }
152 
153     pd->files[pd->num_files] = XtNewString(fn);
154     pd->cur_file_name_idx = pd->num_files;
155     pd->num_files++;
156 }
157 
158 static void
remove_file(Uil_parse_data * pd)159 remove_file(Uil_parse_data *pd)
160 {
161     if (pd->cur_file >= 0)
162     {
163 	close(pd->cur_file);
164 	pd->cur_file--;
165     }
166 }
167 
168 
169 static int
get_file(Uil_parse_data * pd,char * fn)170 get_file(Uil_parse_data *pd, char *fn)
171 {
172     int ret, i;
173 
174     TRACE(("Trying to open %s\n", fn));
175 
176     if ((ret = open(fn, O_RDONLY)) >= 0)
177     {
178 	add_file(pd, fn);
179 
180 	pd->cur_file++;
181 	pd->file_data[pd->cur_file].fd = ret;
182 	pd->file_data[pd->cur_file].pbuf[PARSE_BUF_SIZE/2 - 1] = EOF;
183 	pd->file_data[pd->cur_file].pbuf[PARSE_BUF_SIZE - 1] = EOF;
184 	pd->file_data[pd->cur_file].lexeme = pd->file_data[pd->cur_file].pbuf;
185 	pd->file_data[pd->cur_file].forward =
186 	    pd->file_data[pd->cur_file].pbuf + PARSE_BUF_SIZE - 2;
187 
188 	TRACE(("Opened file: cur_file is %d: fd %d\n",
189 		pd->cur_file, pd->file_data[pd->cur_file].fd));
190 
191 	return ret;
192     }
193 
194     for (i = 0; i < (int)pd->command->include_dir_count; i++)
195     {
196 	char buf[PATHLENMAX];
197 
198 	strcpy(buf, pd->command->include_dir[i]);
199 	if (buf[strlen(buf)] != '/')
200 	{
201 	    strcat(buf, "/");
202 	}
203 
204 	strcat(buf, fn);
205 
206 	TRACE(("Trying to open %s\n", fn));
207 
208 	if ((ret = open(buf, O_RDONLY)) > 0)
209 	{
210 	    add_file(pd, buf);
211 
212 	    pd->cur_file++;
213 	    pd->file_data[pd->cur_file].fd = ret;
214 	    pd->file_data[pd->cur_file].pbuf[PARSE_BUF_SIZE/2 - 1] = EOF;
215 	    pd->file_data[pd->cur_file].pbuf[PARSE_BUF_SIZE - 1] = EOF;
216 	    pd->file_data[pd->cur_file].lexeme =
217 		pd->file_data[pd->cur_file].pbuf;
218 	    pd->file_data[pd->cur_file].forward =
219 		pd->file_data[pd->cur_file].pbuf + PARSE_BUF_SIZE - 2;
220 
221 	    return ret;
222 	}
223     }
224 
225     return -ENOENT;
226 }
227 
228 
229 extern Uil_parse_data *
_uil_parse_init(Uil_command_type * cmd,Uil_compile_desc_type * desc)230 _uil_parse_init(Uil_command_type *cmd, Uil_compile_desc_type *desc)
231 {
232     Uil_parse_data *pd;
233     int fd, i;
234 
235     pd = (Uil_parse_data *)XtCalloc(1, sizeof(Uil_parse_data));
236 
237     pd->command = cmd;
238     pd->desc = desc;
239     pd->root = NULL;
240     pd->hash = (sym_entry **)XtCalloc(sym_k_hash_table_limit,
241 				      sizeof(sym_entry *));
242 
243     pd->cur_file = -1;
244     if ((fd = get_file(pd, cmd->source_file)) < 0)
245     {
246 	_uilmsg(pd, Uil_k_severe_status,
247 	       "Can't open source file: %s\n", cmd->source_file);
248 
249 	_uil_parse_destroy(pd);
250 
251 	return NULL;
252     }
253 
254     pd->include_depth = 0;
255 
256     pd->num_lines = 0;
257     pd->max_lines = 100;
258     pd->lines =
259 	(src_source_record_type *)XtCalloc(pd->max_lines,
260 					   sizeof(src_source_record_type));
261 
262     for (i = 0; i < key_k_keyword_count; i++)
263     {
264 	sym_entry *s;
265 
266 	s = add_symbol(pd, key_table[i].at_name, key_table[i].b_length,
267 		       KEYWORD);
268 
269 	s->e.keyword = &key_table[i];
270     }
271 
272     return pd;
273 }
274 
275 
276 extern void
_uil_parse_destroy(Uil_parse_data * pd)277 _uil_parse_destroy(Uil_parse_data *pd)
278 {
279     int i;
280 
281     if (pd->lines)
282     {
283 	XtFree((char *)pd->lines);
284     }
285 
286     if (pd->lines)
287     {
288 	XtFree((char *)pd->lines);
289     }
290 
291     if (pd->hash)
292     {
293 	XtFree((char *)pd->hash);
294     }
295 
296     if (pd->files)
297     {
298 	for (i = 0; i < pd->num_files; i++)
299 	{
300 	    XtFree(pd->files[i]);
301 	}
302 	XtFree((char *)pd->files);
303     }
304 
305     XtFree((char *)pd);
306 }
307 
308 
309 static char
input(Uil_parse_data * pd)310 input(Uil_parse_data *pd)
311 {
312     int ret;
313     struct _file_data *cf = &pd->file_data[pd->cur_file];
314 
315     cf->forward++;
316     cf->colno++;
317     if (*cf->forward == (char)EOF)
318     {
319 	if (cf->forward - cf->pbuf == PARSE_BUF_SIZE - 1)
320 	{
321 	    if ((ret = read(cf->fd, cf->pbuf,
322 			    PARSE_BUF_SIZE / 2 - 1)) < 0)
323 	    {
324 		_uilmsg(pd, Uil_k_severe_status,
325 		       "Error reading source file: %s fd %d ret %d errno %d\n",
326 		       pd->files[pd->cur_file_name_idx],
327 		       pd->file_data[pd->cur_file].fd, ret, errno);
328 
329 		return EOF;
330 	    }
331 	    else if (ret < PARSE_BUF_SIZE / 2 - 1)
332 	    {
333 		cf->forward = cf->pbuf;
334 		cf->pbuf[ret] = EOF;
335 
336 		if (*cf->forward == '\n')
337 		{
338 		    cf->lineno++;
339 		    cf->colno = 0;
340 		}
341 
342 		return *cf->forward;
343 	    }
344 	    else
345 	    {
346 		cf->forward = cf->pbuf;
347 
348 		if (*cf->forward == '\n')
349 		{
350 		    cf->lineno++;
351 		    cf->colno = 0;
352 		}
353 
354 		return *cf->forward;
355 	    }
356 	}
357 	else if (cf->forward - cf->pbuf == PARSE_BUF_SIZE / 2 - 1)
358 	{
359 	    if ((ret = read(cf->fd, cf->pbuf + PARSE_BUF_SIZE / 2,
360 			    PARSE_BUF_SIZE / 2 - 1)) < 0)
361 	    {
362 		_uilmsg(pd, Uil_k_severe_status,
363 		       "Error reading source file: %s fd %d ret %d errno %d\n",
364 		       pd->files[pd->cur_file_name_idx],
365 		       pd->file_data[pd->cur_file].fd, ret, errno);
366 
367 		return EOF;
368 	    }
369 	    else if (ret < PARSE_BUF_SIZE / 2 - 1)
370 	    {
371 		cf->forward = cf->pbuf + PARSE_BUF_SIZE / 2;
372 		cf->forward[ret] = EOF;
373 
374 		if (*cf->forward == '\n')
375 		{
376 		    cf->lineno++;
377 		    cf->colno = 0;
378 		}
379 
380 		return *cf->forward;
381 	    }
382 	    else
383 	    {
384 		cf->forward = cf->pbuf + PARSE_BUF_SIZE / 2;
385 
386 		if (*cf->forward == '\n')
387 		{
388 		    cf->lineno++;
389 		    cf->colno = 0;
390 		}
391 
392 		return *cf->forward;
393 	    }
394 	}
395 	else
396 	{
397 	    return EOF;
398 	}
399     }
400 
401     if (*cf->forward == '\n')
402     {
403 	cf->lineno++;
404 	cf->colno = 0;
405     }
406 
407     return *cf->forward;
408 }
409 
410 
411 static void
unput(Uil_parse_data * pd)412 unput(Uil_parse_data *pd)
413 {
414     struct _file_data *cf = &pd->file_data[pd->cur_file];
415 
416     if (*cf->forward == '\n')
417     {
418 	cf->lineno--;
419     }
420 
421     if (cf->forward == cf->pbuf)
422     {
423 	cf->forward = cf->pbuf + PARSE_BUF_SIZE - 2;
424     }
425     else if (cf->forward == cf->pbuf + PARSE_BUF_SIZE / 2)
426     {
427 	cf->forward = cf->pbuf + PARSE_BUF_SIZE / 2 - 2;
428     }
429     else
430     {
431 	cf->forward--;
432     }
433 }
434 
435 
436 extern int
_uil_next_lexeme(Uil_parse_data * pd)437 _uil_next_lexeme(Uil_parse_data *pd)
438 {
439     char ch, ch2, *ptr;
440     int have_point;
441     sym_entry *e;
442 
443     pd->file_data[pd->cur_file].lexeme = pd->file_data[pd->cur_file].forward;
444     for (;;)
445     {
446 	ch = input(pd);
447 
448 	switch (ch)
449 	{
450 	case ' ':
451 	case '\t':
452 	case '\v':
453 	case '\r':
454 	case '\b':
455 	case '\n':
456 	    /* skip it */
457 	    pd->file_data[pd->cur_file].lexeme =
458 		pd->file_data[pd->cur_file].forward;
459 	    break;
460 
461 	case '!':
462 	    while ((ch = input(pd)) != '\n' && ch != (char)EOF)
463 		;
464 
465 	    pd->file_data[pd->cur_file].lexeme =
466 		pd->file_data[pd->cur_file].forward;
467 
468 	    TRACE(("Bang comment: lineno: %d\n",
469 		   pd->file_data[pd->cur_file].lineno));
470 
471 	    if (ch != '\n')
472 	    {
473 		return EOF;
474 	    }
475 	    break;
476 
477 	case '/':
478 	    ch2 = input(pd);
479 	    if (ch2 == '*')
480 	    {
481 		while ((ch2 = input(pd)) != (char)EOF)
482 		{
483 		    if (ch2 == '*')
484 		    {
485 			if ((ch = input(pd)) == '/')
486 			{
487 			    pd->file_data[pd->cur_file].lexeme =
488 				pd->file_data[pd->cur_file].forward;
489 
490 			    break;
491 			}
492 		    }
493 		}
494 
495 		TRACE(("C comment: lineno: %d\n",
496 		       pd->file_data[pd->cur_file].lineno));
497 
498 		if (ch == (char)EOF)
499 		{
500 		    return EOF;
501 		}
502 
503 		pd->file_data[pd->cur_file].lexeme =
504 		    pd->file_data[pd->cur_file].forward;
505 	    }
506 	    else
507 	    {
508 		unput(pd);
509 
510 		return ch;
511 	    }
512 	    break;
513 
514 	case '\'':
515 	case '"':
516 	    ch2 = ch;
517 	    ptr = pd->curtok;
518 	    while ((ch = input(pd)) != (char)EOF)
519 	    {
520 		if (ch == '\'' || ch == '"')
521 		{
522 		    if (ch2 != '\\')
523 		    {
524 			break;
525 		    }
526 		}
527 
528 		*ptr = ch;
529 		ptr++;
530 		ch2 = ch;
531 	    }
532 
533 	    if (ch == (char)EOF)
534 	    {
535 		unput(pd);
536 	    }
537 
538 	    *ptr = 0;
539 
540 	    TRACE(("got STRING: %s\n", pd->curtok));
541 
542 	    pd->value.string = XtNewString(pd->curtok);
543 
544 	    return STRING;
545 
546 	case '*':
547 	case '+':
548 	case '-':
549 	case '=':
550 	    TRACE(("got OPERATOR: %c\n", ch));
551 	    return ch;
552 	    break;
553 
554 	case '(':
555 	case ')':
556 	case '{':
557 	case '}':
558 	case ':':
559 	case ';':
560 	case ',':
561 	    TRACE(("got PUNCTUATION: %c\n", ch));
562 	    return ch;
563 	    break;
564 
565 	case '0': case '1': case '2': case '3': case '4':
566 	case '5': case '6': case '7': case '8': case '9':
567 	    /* get number */
568 	    have_point = False;
569 	    ptr = pd->curtok;
570 	    *ptr = ch;
571 	    ptr++;
572 	    while ((ch = input(pd)) != (char)EOF)
573 	    {
574 		if (!isdigit(ch) || ch != '.')
575 		{
576 		    break;
577 		}
578 
579 		if (ch == '.' && have_point)
580 		{
581 		    break;
582 		}
583 		else if (ch == '.')
584 		{
585 		    have_point = True;
586 		}
587 
588 		*ptr = ch;
589 		ptr++;
590 	    }
591 
592 	    unput(pd);
593 
594 	    *ptr = 0;
595 
596 	    TRACE(("got NUMBER: %s\n", pd->curtok));
597 
598 	    if (have_point)
599 	    {
600 		pd->value.real = atof(pd->curtok);
601 		return REAL;
602 	    }
603 	    else
604 	    {
605 		pd->value.integer = atoi(pd->curtok);
606 		return INT;
607 	    }
608 
609 	case EOF:
610 	    TRACE(("EOF\n"));
611 	    TRACE(("CURRENT FILE: %s line: %d\n",
612 		   pd->files[pd->cur_file_name_idx],
613 		   pd->file_data[pd->cur_file].lineno));
614 
615 	    remove_file(pd);
616 
617 	    if (pd->cur_file < 0)
618 	    {
619 		return EOF;
620 	    }
621 
622 	    break;
623 
624 	default:
625 	    if (isalpha(ch))
626 	    {
627 		ptr = pd->curtok;
628 		*ptr = ch;
629 		ptr++;
630 		while ((ch = input(pd)) != (char)EOF)
631 		{
632 		    if (!isalpha(ch) && !isdigit(ch) && ch != '_')
633 		    {
634 			break;
635 		    }
636 		    *ptr = ch;
637 		    ptr++;
638 		}
639 
640 		unput(pd);
641 
642 		*ptr = 0;
643 
644 		TRACE(("got SYMBOL: %s\n", pd->curtok));
645 
646 		if ((e = find_symbol(pd, pd->curtok, strlen(pd->curtok)))
647 		    != NULL)
648 		{
649 		    pd->value.sym = e;
650 
651 		    return e->type;
652 		}
653 
654 		pd->value.sym = add_symbol(pd, pd->curtok, strlen(pd->curtok),
655 					   SYMBOL);
656 
657 		return SYMBOL;
658 	    }
659 	    else
660 	    {
661 		_uilmsg(pd, Uil_k_severe_status,
662 		       "Invalid lexical component: '%c' : %02x %s %d\n",
663 		       ch, (unsigned char)ch,
664 		       pd->files[pd->cur_file_name_idx],
665 		       pd->file_data[pd->cur_file].lineno);
666 
667 		return EOF;
668 	    }
669 
670 	    break;
671 	}
672     }
673 }
674