Split out yyerror.
[fw/sdcc] / src / altlex.c
1 /** @file altlex.c
2     An alternate lexer to SDCC.lex.
3     In development - ie messy and just plain wrong.
4     Inspired by the gcc lexer, c-lex.c.
5 */
6 #include "common.h"
7 #include "reswords.h"
8 #include <assert.h>
9
10 #define DUMP_OUTPUT             0
11
12 /* Right.  What are the parts of the C stream?  From SDCC.lex:
13    D = [0..9]           digits
14    L = [a..z A..Z _]    alphanumerics and _
15    H = [a..f A..F 0-9]  Hex digits
16    E = [eE+-0-9]        Digits in a float
17    FS = [fFlL]          Specifiers for a float
18    IS = [uUlL]          Specifiers for a int
19
20    L[LD]*               A 'token' - cant think of a good name
21                         Check tokens against the reserved words.
22                         If match 
23                                 return the token id.
24                         else 
25                                 If in the typedef table, do stuff...
26                                 Blah.  See check_type()
27    0[xX]{H}+            Hex number - PENDING: specifiers
28    0{D}+                Octal number - PENDING: specifiers
29    {D}+                 Decimal - PENDING: specifiers
30    Floats               PENDING
31    
32    Exceptions:
33    Comment start        Strip until end of comment.
34    ...                  Ellipses
35
36    So the inputs are:
37       Skip whitespace
38       switch class
39          L      Try to read a token
40          D      Try to read a number
41          Punct  Try to read punct
42 */      
43
44 extern int fatalError;
45 extern int lineno;
46 extern char *filename;
47
48 FILE *yyin;
49
50 int yylineno;
51 char *currFname;
52 char *yytext;
53
54 static char linebuf[10000];
55 static int linepos, linelen;
56 static int end_of_file;
57
58 #ifdef __GNUC__
59 #define INLINE  inline
60 #else
61 #define INLINE 
62 #endif
63
64 #define ERRSINK stderr
65
66 static void error(const char *sz, ...)
67 {
68     va_list ap;
69     fatalError++;
70     
71     if (filename && lineno) {
72         fprintf(ERRSINK, "%s(%d):",filename,lineno);
73     }
74     fprintf(ERRSINK, "error *** ");
75     va_start(ap, sz);
76     vfprintf(ERRSINK, sz, ap);
77     va_end(ap);
78     fprintf(ERRSINK, "\n");
79     fflush(ERRSINK);
80 }
81
82 static int underflow(void)
83 {
84     linelen = fread(linebuf, 1, sizeof(linebuf), yyin);
85     if (linelen <= 0)
86         return EOF;
87     linepos = 0;
88     return linebuf[linepos++];
89 }
90
91 static int INLINE ygetc(void)
92 {
93     if (linepos < linelen)
94         return linebuf[linepos++];
95     else
96         return underflow();
97 };
98
99 static int INLINE yungetc(int c)
100 {
101     linebuf[--linepos] = c;
102     return 0;
103 }
104
105 #define GETC()          ygetc()
106 #define UNGETC(_a)      yungetc(_a)
107
108 //#define GETC()                fgetc(yyin);
109 //#define UNGETC(_a)    ungetc(_a, yyin)
110 #define ISL(_a)         (isalnum(_a) || _a == '_')
111 #define ISALNUM(_a)     isalnum(_a)
112 #define ISHEX(_a)       isxdigit(_a)
113
114 static char *stringLiteral (void)
115 {
116     static char line[1000];
117     int ch;
118     char *str = line;
119        
120     *str++ = '\"'                       ;
121     /* put into the buffer till we hit the */
122     /* first \" */
123     while (1) {
124
125         ch = GETC();
126         if (!ch)            break       ; /* end of input */
127         /* if it is a \ then everything allowed */
128         if (ch == '\\') {
129             *str++ = ch     ; /* backslash in place */
130             *str++ = GETC()             ; /* following char in place */
131             continue                    ;      /* carry on */
132         }
133              
134         /* if new line we have a new line break */
135         if (ch == '\n') break           ;
136          
137         /* if this is a quote then we have work to do */
138         /* find the next non whitespace character     */
139         /* if that is a double quote then carry on    */
140         if (ch == '\"') {
141          
142             while ((ch = GETC()) && isspace(ch)) ;
143             if (!ch) break              ; 
144             if (ch != '\"') {
145                 UNGETC(ch)                      ;
146                 break                   ;
147             }
148                   
149             continue            ;
150         }
151         *str++  = ch;     
152     }  
153     *str++ = '\"'                       ;
154     *str = '\0';
155     return line;
156 }
157
158 static void discard_comments(int type)
159 {
160     int c;
161     if (type == '*') {
162         do {
163             c = GETC();
164             if (c == '*') {
165                 c = GETC();
166                 if (c == '/')
167                     return;
168             }
169             else if (c == EOF)
170                 return;
171         } while (1);
172     }
173     else if (type == '/') {
174         do {
175             c = GETC();
176         } while (c != '\n' && c != EOF);
177     }
178     else {
179         assert(0);
180     }
181 }
182
183 /* will return 1 if the string is a part
184    of a target specific keyword */
185 static INLINE int isTargetKeyword(const char *s)
186 {
187     int i;
188     
189     if (port->keywords == NULL)
190         return 0;
191     for ( i = 0 ; port->keywords[i] ; i++ ) {
192         if (strcmp(port->keywords[i],s) == 0)
193             return 1;
194     }
195     
196     return 0;
197 }
198
199 static INLINE int check_token(const char *sz)
200 {
201     const struct reserved_words *p;
202     p = is_reserved_word(sz, strlen(sz));
203     if (p) {
204         if (!p->is_special || isTargetKeyword(sz))
205             return p->token;
206     }
207
208     /* check if it is in the typedef table */
209     if (findSym(TypedefTab,NULL,sz)) {
210         strcpy(yylval.yychar,sz);
211         return TYPE_NAME;
212     }
213     else   {
214         strcpy (yylval.yychar,sz);
215         return IDENTIFIER;
216     }
217 }
218
219 static void handle_pragma(void)
220 {
221     char line[128], *p;
222     int c;
223
224     c = GETC();
225     while (c == '\t' || c == ' ')
226         c = GETC();
227     p = line;
228     while (!isspace(c)) {
229         *p++ = c;
230         c = GETC();
231     }
232     *p = '\0';
233     if (line[0] == '\0')
234         error("Missing argument to pragma");
235     else {
236         /* First give the port a chance */
237         if (port->process_pragma && !port->process_pragma(line))
238             return;
239         /* PENDING: all the SDCC shared pragmas */
240         /* Nothing handled it */
241         error("Unrecognised #pragma %s", line);
242     }
243 }
244
245 static void handle_line(void)
246 {
247     int c;
248     char line[128], *p;
249
250     c = GETC();
251     while (c == '\t' || c == ' ')
252         c = GETC();
253     p = line;
254     while (isdigit(c)) {
255         *p++ = c;
256         c = GETC();
257     }
258     *p = '\0';
259     if (line[0] == '\0')
260         error("Error in number in #line");
261     /* This is weird but cpp seems to add an extra three to the line no */
262     yylineno = atoi(line) - 3;
263     lineno = yylineno;
264     /* Fetch the filename if there is one */
265     while (c == '\t' || c == ' ')
266         c = GETC();
267     if (c == '\"') {
268         p = line;
269         c = GETC();
270         while (c != '\"' && c != EOF && c != '\n') {
271             *p++ = c;
272             c = GETC();
273         }
274         if (c == '\"') {
275             *p = '\0';
276             currFname = gc_strdup(line);
277         }
278         filename = currFname;
279     }
280 }
281
282 static INLINE void invalid_directive(void)
283 {
284     error("Invalid directive");
285 }
286
287 static INLINE int check_newline(void)
288 {
289     int c;
290     yylineno++;
291     lineno = yylineno;
292
293     /* Skip any leading white space */
294     c = GETC();
295     while (c == '\t' || c == ' ')
296         c = GETC();
297     /* Were only interested in #something */
298     if (c != '#')
299         return c;
300     c = GETC();
301     while (c == '\t' || c == ' ')
302         c = GETC();
303     /* The text in the stream is the type of directive */
304     switch (c) {
305     case 'l':
306         /* Start of line? */
307         if (GETC() == 'i' && GETC() == 'n' && GETC() == 'e') {
308             c = GETC();
309             if (c == '\t' || c == ' ')
310                 handle_line();
311             else
312                 invalid_directive();
313         }
314         else
315             invalid_directive();
316         break;
317     case 'p':
318         /* Start of pragma? */
319         if (GETC() == 'r' && GETC() == 'a' && GETC() == 'g' &&
320             GETC() == 'm' && GETC() == 'a') {
321             c = GETC();
322             if (c == '\t' || c == ' ')
323                 handle_pragma();
324             else
325                 invalid_directive();
326         }
327         else
328             invalid_directive();
329         break;
330     default:
331         invalid_directive();
332     }
333     /* Discard from here until the start of the next line */
334     while (c != '\n' && c != EOF)
335         c = GETC();
336     return c;
337 }
338
339 static int skip_whitespace(int c)
340 {
341     while (1) {
342         switch (c) {
343         case ' ':
344         case '\t':
345         case '\f':
346         case '\v':
347         case '\b':
348         case '\r':
349             c = GETC();
350             break;
351         case '\n':
352             c = check_newline();
353         default:
354             return c;
355         }
356     }
357 }
358
359 void yyerror(const char *s)
360 {
361    if (end_of_file)
362        error("%s at end of of input", s);
363    else if (yytext[0] == '\0')
364        error("%s at null character", s);
365    else if (yytext[0] == '"')
366        error("%s before string constant", s);
367    else if (yytext[0] == '\'')
368        error("%s before character constant", s);
369    else 
370        error("%s before %s", s, yytext);
371 }
372
373 static int _yylex(void)
374 {
375     int c;
376     static char line[128];
377     char *p;
378
379     yytext = line;
380
381     c = GETC();
382     while (1) {
383         switch (c) {
384         case ' ':
385         case '\t':
386         case '\f':
387         case '\v':
388         case '\b':
389             /* Skip whitespace */
390             c = GETC();
391             break;
392         case '\r':
393         case '\n':
394             c = skip_whitespace(c);
395             break;
396         case '#':
397             UNGETC(c);
398             c = check_newline();
399             break;
400         default:
401             goto past_ws;
402         }
403     }
404
405  past_ws:
406     /* Handle comments first */
407     if (c == '/') {
408         int c2 = GETC();
409         if (c2 == '*' || c2 == '/') {
410             discard_comments(c2);
411             c = GETC();
412         }
413         else
414             UNGETC(c2);
415     }
416     switch (c) {
417     case EOF:
418         end_of_file = TRUE;
419         line[0] = '\0';
420         return 0;
421     case 'a': case 'b': case 'c': case 'd':
422     case 'e': case 'f': case 'g': case 'h':
423     case 'i': case 'j': case 'k': case 'l':
424     case 'm': case 'n': case 'o': case 'p':
425     case 'q': case 'r': case 's': case 't':
426     case 'u': case 'v': case 'w': case 'x':
427     case 'y': case 'z':
428     case 'A': case 'B': case 'C': case 'D':
429     case 'E': case 'F': case 'G': case 'H':
430     case 'I': case 'J': case 'K': case 'L':
431     case 'M': case 'N': case 'O': case 'P':
432     case 'Q': case 'R': case 'S': case 'T':
433     case 'U': case 'V': case 'W': case 'X':
434     case 'Y': case 'Z':
435     case '_':
436         /* Start of a token.  Parse. */
437         p = line;
438         *p++ = c;
439         c = GETC();
440         while (ISL(c)) {
441             *p++ = c;
442             c = GETC();
443         }
444         *p = '\0';
445         UNGETC(c);
446         return check_token(line);
447     case '0': case '1':
448     case '2': case '3': case '4': case '5':
449     case '6': case '7': case '8': case '9':
450         p = line;
451         *p++ = c;
452         c = GETC();
453         if (c == 'x' || c == 'X') {
454             *p++ = c;
455             c = GETC();
456         }
457         while (ISHEX(c)) {
458             *p++ = c;
459             c = GETC();
460         }
461         *p = '\0';
462         UNGETC(c);
463         yylval.val = constVal(line);
464         return CONSTANT;
465     case '\"':
466         /* A string */
467         p = stringLiteral();
468         yylval.val = strVal(p);
469         return(STRING_LITERAL);
470     case '\'':
471         /* Possible formats:
472            ['\n', '\\', '\'', '\"'...]
473            ['a'...]
474         */
475         p = line;
476         *p++ = c;
477         c = GETC();
478         if (c == '\\') {
479             *p++ = c;
480             c = GETC();
481             /* Fall through */
482         }
483         *p++ = c;
484         c = GETC();
485         *p++ = c;
486         *p = '\0';
487         if (c != '\'') {
488             error("Unrecognised character constant %s", line);
489         }
490         yylval.val = charVal(line);
491         return CONSTANT;
492     case '=':
493     case '&':
494     case '!':
495     case '-':
496     case '+':
497     case '*':
498     case '/':
499     case '%':
500     case '<':
501     case '>':
502     case '^':
503     case '|': {
504         /* Cases which can be compounds */
505         /* The types and classes of composites are:
506            >>= <<=
507            += -= *= /= %= &= ^= |=
508            >> << ++ --
509            && ||
510            <= >= == !=
511            ->
512            So a composite started by char 'x' can be:
513            1. Followed by itself then an equals
514            2. Followed by itself
515            3. Followed by an equals
516            4. Be a '->'
517            5. Be by itself
518         */
519         int next = GETC();
520         /* Class 1 and 2 */
521         if (next == c) {
522             next = GETC();
523             /* Class 1 */
524             if (next == '=') {
525                 switch (c) {
526                 case '>':       // >>=
527                     yylval.yyint = RIGHT_ASSIGN;
528                     return RIGHT_ASSIGN;
529                 case '<':       // <<=
530                     yylval.yyint = LEFT_ASSIGN;
531                     return LEFT_ASSIGN;
532                 default:
533                     error("Unrecognised token %c%c=", c, c);
534                 }
535             }
536             else {
537                 /* Push the next char back on and find the class */
538                 UNGETC(next);
539                 /* Case 2 */
540                 switch (c) {
541                 case '>':       // >>
542                     return RIGHT_OP;
543                 case '<':       // <<
544                     return LEFT_OP;
545                 case '+':
546                     return INC_OP;
547                 case '-':
548                     return DEC_OP;
549                 case '&':
550                     return AND_OP;
551                 case '|':
552                     return OR_OP;
553                 case '=':
554                     return EQ_OP;
555                 default:
556                     error("Unrecognised token %c%c", c, c);
557                 }
558             }
559         }
560         /* Case 3 */
561         else if (next == '=') {
562             int result = 0;
563             switch (c) {
564             case '+':
565                 result = ADD_ASSIGN; break;
566             case '-':
567                 result = SUB_ASSIGN; break;
568             case '*':
569                 result = MUL_ASSIGN; break;
570             case '/':
571                 result = DIV_ASSIGN; break;
572             case '%':
573                 result = MOD_ASSIGN; break;
574             case '&':
575                 result = AND_ASSIGN; break;
576             case '^':
577                 result = XOR_ASSIGN; break;
578             case '|':
579                 result = OR_ASSIGN; break;
580             case '<':
581                 result = LE_OP; break;
582             case '>':
583                 result = GE_OP; break;
584             case '!':
585                 result = NE_OP; break;
586             default:
587                 error("Unrecognised token %c=", c);
588             }
589             if (result) {
590                 yylval.yyint = result;
591                 return result;
592             }
593         }
594         /* Case 4 */
595         else if (c == '-' && next == '>') {
596             return PTR_OP;
597         }
598         /* Case 5 */
599         else {
600             UNGETC(next);
601             return c;
602         }
603         break;
604     }
605     case '{':
606         NestLevel++;
607         return c;
608     case '}':
609         NestLevel--;
610         return c;
611     case '.':
612         c = GETC();
613         if (c == '.') {
614             c = GETC();
615             if (c == '.') {
616                 return VAR_ARGS;
617             }
618         }
619         UNGETC(c);
620         return '.';
621     case '[': case ']':
622         return c;
623     case ',':
624     case ':':
625     case '(': case ')':
626     case '~':
627     case '?':
628     case ';':
629         /* Special characters that cant be part of a composite */
630         return c;
631     default:
632         error("Unhandled character %c", c);
633     }
634     return 0;
635 }
636
637 #define ENTRY(_a)       case (_a): printf(#_a); break;
638
639 int yylex(void)
640 {
641     int ret = _yylex();
642 #if DUMP_OUTPUT
643     static int lastpos = 0;
644     char tmp;
645
646     printf("Returning ");
647     switch (ret) {
648         /* Wrapper */
649         ENTRY(IDENTIFIER);
650         ENTRY(TYPE_NAME);
651         ENTRY(CONSTANT);
652         ENTRY(STRING_LITERAL);
653         ENTRY(SIZEOF);
654         ENTRY(PTR_OP);
655         ENTRY(INC_OP);
656         ENTRY(DEC_OP);
657         ENTRY(LEFT_OP);
658         ENTRY(RIGHT_OP);
659         ENTRY(LE_OP);
660         ENTRY(GE_OP);
661         ENTRY(EQ_OP);
662         ENTRY(NE_OP);
663         ENTRY(AND_OP);
664         ENTRY(OR_OP);
665         ENTRY(MUL_ASSIGN);
666         ENTRY(DIV_ASSIGN);
667         ENTRY(MOD_ASSIGN);
668         ENTRY(ADD_ASSIGN);
669         ENTRY(SUB_ASSIGN);
670         ENTRY(LEFT_ASSIGN);
671         ENTRY(RIGHT_ASSIGN);
672         ENTRY(AND_ASSIGN);
673         ENTRY(XOR_ASSIGN);
674         ENTRY(OR_ASSIGN);
675         ENTRY(TYPEDEF);
676         ENTRY(EXTERN);
677         ENTRY(STATIC);
678         ENTRY(AUTO);
679         ENTRY(REGISTER);
680         ENTRY(CODE);
681         ENTRY(EEPROM);
682         ENTRY(INTERRUPT);
683         ENTRY(SFR);
684         ENTRY(AT);
685         ENTRY(SBIT);
686         ENTRY(REENTRANT);
687         ENTRY(USING);
688         ENTRY(XDATA);
689         ENTRY(DATA);
690         ENTRY(IDATA);
691         ENTRY(PDATA);
692         ENTRY(VAR_ARGS);
693         ENTRY(CRITICAL);
694         ENTRY(NONBANKED);
695         ENTRY(BANKED);
696         ENTRY(CHAR);
697         ENTRY(SHORT);
698         ENTRY(INT);
699         ENTRY(LONG);
700         ENTRY(SIGNED);
701         ENTRY(UNSIGNED);
702         ENTRY(FLOAT);
703         ENTRY(DOUBLE);
704         ENTRY(CONST);
705         ENTRY(VOLATILE);
706         ENTRY(VOID);
707         ENTRY(BIT);
708         ENTRY(STRUCT);
709         ENTRY(UNION);
710         ENTRY(ENUM);
711         ENTRY(ELIPSIS);
712         ENTRY(RANGE);
713         ENTRY(FAR);
714         ENTRY(_XDATA);
715         ENTRY(_CODE);
716         ENTRY(_GENERIC);
717         ENTRY(_NEAR);
718         ENTRY(_PDATA);
719         ENTRY(_IDATA);
720         ENTRY(_EEPROM);
721         ENTRY(CASE);
722         ENTRY(DEFAULT);
723         ENTRY(IF);
724         ENTRY(ELSE);
725         ENTRY(SWITCH);
726         ENTRY(WHILE);
727         ENTRY(DO);
728         ENTRY(FOR);
729         ENTRY(GOTO);
730         ENTRY(CONTINUE);
731         ENTRY(BREAK);
732         ENTRY(RETURN);
733         ENTRY(INLINEASM);
734         ENTRY(IFX);
735         ENTRY(ADDRESS_OF);
736         ENTRY(GET_VALUE_AT_ADDRESS);
737         ENTRY(SPIL);
738         ENTRY(UNSPIL);
739         ENTRY(GETHBIT);
740         ENTRY(BITWISEAND);
741         ENTRY(UNARYMINUS);
742         ENTRY(IPUSH);
743         ENTRY(IPOP);
744         ENTRY(PCALL);
745         ENTRY(ENDFUNCTION);
746         ENTRY(JUMPTABLE);
747         ENTRY(RRC);
748         ENTRY(RLC);
749         ENTRY(CAST);
750         ENTRY(CALL);
751         ENTRY(PARAM);
752         ENTRY(NULLOP);
753         ENTRY(BLOCK);
754         ENTRY(LABEL);
755         ENTRY(RECEIVE);
756         ENTRY(SEND);
757     default:
758         printf("default: %c", ret);
759     }
760     tmp = linebuf[linepos];
761     linebuf[linepos] = '\0';
762     printf(" for %s (%u bytes)\n", linebuf + lastpos, linepos - lastpos);
763     linebuf[linepos] = tmp;
764     lastpos = linepos;
765     fflush(stdout);
766 #endif
767     return ret;
768 }
769
770 #define TEST(_a)        (_a) ? (void)0 : printf("Test %s failed\n", #_a);
771
772 int altlex_testparse(const char *input)
773 {
774     /* Fiddle with the read-ahead buffer to insert ourselves */
775     strcpy(linebuf, input);
776     linelen = strlen(linebuf)+1;
777     linepos = 0;
778     
779     return yylex();
780 }
781
782 int altlex_testchar(const char *input)
783 {
784     value *val;
785     if (altlex_testparse(input) != CONSTANT)
786         return -2;
787     val = yylval.val;
788     if (val->type->class != SPECIFIER)
789         return -3;
790     if (SPEC_NOUN(val->type) != V_CHAR)
791         return -4;
792     if (SPEC_SCLS(val->type) != S_LITERAL)
793         return -5;
794     return SPEC_CVAL(val->type).v_int;
795 }
796
797 int altlex_testnum(const char *input)
798 {
799     value *val;
800     if (altlex_testparse(input) != CONSTANT)
801         return -2;
802     val = yylval.val;
803     if (val->type->class != SPECIFIER)
804         return -3;
805     if (SPEC_NOUN(val->type) != V_INT)
806         return -4;
807     if (SPEC_SCLS(val->type) != S_LITERAL)
808         return -5;
809     if (SPEC_USIGN(val->type))
810         return SPEC_CVAL(val->type).v_uint;
811     else
812         return SPEC_CVAL(val->type).v_int;
813 }
814
815 int altlex_runtests(void)
816 {
817     /* These conditions are ripped directly from SDCC.lex */
818     /* First check the parsing of the basic tokens */
819     TEST(altlex_testparse(">>=") == RIGHT_ASSIGN);
820     TEST(altlex_testparse("<<=") == LEFT_ASSIGN);
821     TEST(altlex_testparse("+=") == ADD_ASSIGN);
822     TEST(altlex_testparse("-=") == SUB_ASSIGN);
823     TEST(altlex_testparse("*=") == MUL_ASSIGN);
824     TEST(altlex_testparse("/=") == DIV_ASSIGN);
825     TEST(altlex_testparse("%=") == MOD_ASSIGN);
826     TEST(altlex_testparse("&=") == AND_ASSIGN);
827     TEST(altlex_testparse("^=") == XOR_ASSIGN);
828     TEST(altlex_testparse("|=") == OR_ASSIGN);
829     TEST(altlex_testparse(">>") == RIGHT_OP);
830     TEST(altlex_testparse("<<") == LEFT_OP);
831     TEST(altlex_testparse("++") == INC_OP);
832     TEST(altlex_testparse("--") == DEC_OP);
833     TEST(altlex_testparse("->") == PTR_OP);
834     TEST(altlex_testparse("&&") == AND_OP);
835     TEST(altlex_testparse("||") == OR_OP);
836     TEST(altlex_testparse("<=") == LE_OP);
837     TEST(altlex_testparse(">=") == GE_OP);
838     TEST(altlex_testparse("==") == EQ_OP);
839     TEST(altlex_testparse("!=") == NE_OP);
840     TEST(altlex_testparse(";") == ';');
841     TEST(altlex_testparse("{") == '{');
842     TEST(altlex_testparse("}") == '}');
843     TEST(altlex_testparse(",") == ',');
844     TEST(altlex_testparse(":") == ':');
845     TEST(altlex_testparse("=") == '=');
846     TEST(altlex_testparse("(") == '(');
847     TEST(altlex_testparse(")") == ')');
848     TEST(altlex_testparse("[") == '[');
849     TEST(altlex_testparse("]") == ']');
850     TEST(altlex_testparse(".") == '.');
851     TEST(altlex_testparse("&") == '&');
852     TEST(altlex_testparse("!") == '!');
853     TEST(altlex_testparse("~") == '~');
854     TEST(altlex_testparse("-") == '-');
855     TEST(altlex_testparse("+") == '+');
856     TEST(altlex_testparse("*") == '*');
857     TEST(altlex_testparse("/") == '/');
858     TEST(altlex_testparse("%") == '%');
859     TEST(altlex_testparse("<") == '<');
860     TEST(altlex_testparse(">") == '>');
861     TEST(altlex_testparse("^") == '^');
862     TEST(altlex_testparse("|") == '|');
863     TEST(altlex_testparse("?") == '?');
864
865     /* Now some character constants */
866     TEST(altlex_testchar("'1'") == '1');
867     TEST(altlex_testchar("'a'") == 'a');
868     TEST(altlex_testchar("'A'") == 'A');
869     TEST(altlex_testchar("'z'") == 'z');
870     TEST(altlex_testchar("'Z'") == 'Z');
871     TEST(altlex_testchar("'\n'") == '\n');
872     TEST(altlex_testchar("'\\\\'") == '\\');
873     TEST(altlex_testchar("'\\''") == '\'');
874
875     /* And some numbers */
876     TEST(altlex_testnum("0") == 0);
877     TEST(altlex_testnum("1") == 1);
878     TEST(altlex_testnum("075") == 075);
879     TEST(altlex_testnum("0xfeed") == 0xfeed);
880     TEST(altlex_testnum("0xFEED") == 0xFEED);
881     TEST(altlex_testnum("0x00005678") == 0x5678);
882
883     /* Keywords */
884     TEST(altlex_testparse("auto") == AUTO);
885     TEST(altlex_testparse("break") == BREAK);
886     TEST(altlex_testparse("case") == CASE);
887     TEST(altlex_testparse("char") == CHAR);
888     TEST(altlex_testparse("const") == CONST);
889     TEST(altlex_testparse("continue") == CONTINUE);
890     TEST(altlex_testparse("default") == DEFAULT);
891     TEST(altlex_testparse("do") == DO);
892     /* Prints a warning */
893     //    TEST(altlex_testparse("double") == FLOAT);
894     TEST(altlex_testparse("else") == ELSE);
895     TEST(altlex_testparse("enum") == ENUM);
896     TEST(altlex_testparse("extern") == EXTERN);
897     TEST(altlex_testparse("float") == FLOAT);
898     TEST(altlex_testparse("for") == FOR);
899     TEST(altlex_testparse("goto") == GOTO);
900     TEST(altlex_testparse("if") == IF);
901     TEST(altlex_testparse("int") == INT);
902     TEST(altlex_testparse("interrupt") == INTERRUPT);
903     TEST(altlex_testparse("long") == LONG);
904     TEST(altlex_testparse("register") == REGISTER);
905     TEST(altlex_testparse("return") == RETURN);
906     TEST(altlex_testparse("short") == SHORT);
907     TEST(altlex_testparse("signed") == SIGNED);
908     TEST(altlex_testparse("sizeof") == SIZEOF);
909     TEST(altlex_testparse("static") == STATIC);
910     TEST(altlex_testparse("struct") == STRUCT);
911     TEST(altlex_testparse("switch") == SWITCH);
912     TEST(altlex_testparse("typedef") == TYPEDEF);
913     TEST(altlex_testparse("union") == UNION);
914     TEST(altlex_testparse("unsigned") == UNSIGNED);
915     TEST(altlex_testparse("void") == VOID);
916     TEST(altlex_testparse("volatile") == VOLATILE);
917     TEST(altlex_testparse("while") == WHILE);
918     TEST(altlex_testparse("...") == VAR_ARGS);
919
920 #if 0
921     /* Platform specific keywords */
922     TEST(altlex_testparse("sram") ==)         { count(); TKEYWORD(XDATA);}
923     TEST(altlex_testparse("using") ==)        { count(); TKEYWORD(USING); }
924     TEST(altlex_testparse("near") ==)          { count(); TKEYWORD(DATA);}
925     TEST(altlex_testparse("at") ==)            { count(); TKEYWORD(AT)  ; }
926     TEST(altlex_testparse("bit") ==)           { count(); TKEYWORD(BIT) ; }
927     TEST(altlex_testparse("code") ==)         { count(); TKEYWORD(CODE); }
928     TEST(altlex_testparse("critical") ==)     { count(); TKEYWORD(CRITICAL); } 
929     TEST(altlex_testparse("data") ==)          { count(); TKEYWORD(DATA);   }
930     TEST(altlex_testparse("far") ==)          { count(); TKEYWORD(XDATA);  }
931     TEST(altlex_testparse("eeprom") ==)       { count(); TKEYWORD(EEPROM);  }
932     TEST(altlex_testparse("flash") ==)        { count(); TKEYWORD(CODE);}
933     TEST(altlex_testparse("idata") ==)        { count(); TKEYWORD(IDATA);}
934     TEST(altlex_testparse("nonbanked") ==)    { count(); TKEYWORD(NONBANKED);}
935     TEST(altlex_testparse("banked") ==)       { count(); TKEYWORD(BANKED);}
936     TEST(altlex_testparse("pdata") ==)        { count(); TKEYWORD(PDATA); }
937     TEST(altlex_testparse("reentrant") ==)    { count(); TKEYWORD(REENTRANT);}
938     TEST(altlex_testparse("sfr") ==)           { count(); TKEYWORD(SFR) ; }
939     TEST(altlex_testparse("sbit") ==)          { count(); TKEYWORD(SBIT)        ; }
940     TEST(altlex_testparse("xdata") ==)        { count(); TKEYWORD(XDATA); }
941     TEST(altlex_testparse("_data") ==)         { count(); TKEYWORD(_NEAR); }
942     TEST(altlex_testparse("_code") ==)         { count(); TKEYWORD(_CODE); }
943     TEST(altlex_testparse("_eeprom") ==)      { count(); TKEYWORD(_EEPROM); }
944     TEST(altlex_testparse("_flash") ==)       { count(); TKEYWORD(_CODE); }
945     TEST(altlex_testparse("_generic") ==)     { count(); TKEYWORD(_GENERIC); }
946     TEST(altlex_testparse("_near") ==)         { count(); TKEYWORD(_NEAR); }
947     TEST(altlex_testparse("_sram") ==)        { count(); TKEYWORD(_XDATA);}
948     TEST(altlex_testparse("_xdata") ==)       { count(); TKEYWORD(_XDATA);}
949     TEST(altlex_testparse("_pdata") ==)       { count(); TKEYWORD(_PDATA); }
950     TEST(altlex_testparse("_idata") ==)       { count(); TKEYWORD(_IDATA); }
951 #endif
952
953     return 0;
954 }