add 'on demand' integer promotion
[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         if (c == 'U' || c == 'u' || c == 'L' || c == 'l') {
462             *p++ = c;
463             c = GETC();
464         }
465         if (c == 'U' || c == 'u' || c == 'L' || c == 'l') {
466             *p++ = c;
467             c = GETC();
468         }
469         *p = '\0';
470         UNGETC(c);
471         yylval.val = constVal(line);
472         return CONSTANT;
473     case '\"':
474         /* A string */
475         p = stringLiteral();
476         yylval.val = strVal(p);
477         return(STRING_LITERAL);
478     case '\'':
479         /* Possible formats:
480            ['\n', '\\', '\'', '\"'...]
481            ['a'...]
482         */
483         p = line;
484         *p++ = c;
485         c = GETC();
486         if (c == '\\') {
487             *p++ = c;
488             c = GETC();
489             /* Fall through */
490         }
491         *p++ = c;
492         c = GETC();
493         *p++ = c;
494         *p = '\0';
495         if (c != '\'') {
496             error("Unrecognised character constant %s", line);
497         }
498         yylval.val = charVal(line);
499         return CONSTANT;
500     case '=':
501     case '&':
502     case '!':
503     case '-':
504     case '+':
505     case '*':
506     case '/':
507     case '%':
508     case '<':
509     case '>':
510     case '^':
511     case '|': {
512         /* Cases which can be compounds */
513         /* The types and classes of composites are:
514            >>= <<=
515            += -= *= /= %= &= ^= |=
516            >> << ++ --
517            && ||
518            <= >= == !=
519            ->
520            So a composite started by char 'x' can be:
521            1. Followed by itself then an equals
522            2. Followed by itself
523            3. Followed by an equals
524            4. Be a '->'
525            5. Be by itself
526         */
527         int next = GETC();
528         /* Class 1 and 2 */
529         if (next == c) {
530             next = GETC();
531             /* Class 1 */
532             if (next == '=') {
533                 switch (c) {
534                 case '>':       // >>=
535                     yylval.yyint = RIGHT_ASSIGN;
536                     return RIGHT_ASSIGN;
537                 case '<':       // <<=
538                     yylval.yyint = LEFT_ASSIGN;
539                     return LEFT_ASSIGN;
540                 default:
541                     error("Unrecognised token %c%c=", c, c);
542                 }
543             }
544             else {
545                 /* Push the next char back on and find the class */
546                 UNGETC(next);
547                 /* Case 2 */
548                 switch (c) {
549                 case '>':       // >>
550                     return RIGHT_OP;
551                 case '<':       // <<
552                     return LEFT_OP;
553                 case '+':
554                     return INC_OP;
555                 case '-':
556                     return DEC_OP;
557                 case '&':
558                     return AND_OP;
559                 case '|':
560                     return OR_OP;
561                 case '=':
562                     return EQ_OP;
563                 default:
564                     error("Unrecognised token %c%c", c, c);
565                 }
566             }
567         }
568         /* Case 3 */
569         else if (next == '=') {
570             int result = 0;
571             switch (c) {
572             case '+':
573                 result = ADD_ASSIGN; break;
574             case '-':
575                 result = SUB_ASSIGN; break;
576             case '*':
577                 result = MUL_ASSIGN; break;
578             case '/':
579                 result = DIV_ASSIGN; break;
580             case '%':
581                 result = MOD_ASSIGN; break;
582             case '&':
583                 result = AND_ASSIGN; break;
584             case '^':
585                 result = XOR_ASSIGN; break;
586             case '|':
587                 result = OR_ASSIGN; break;
588             case '<':
589                 result = LE_OP; break;
590             case '>':
591                 result = GE_OP; break;
592             case '!':
593                 result = NE_OP; break;
594             default:
595                 error("Unrecognised token %c=", c);
596             }
597             if (result) {
598                 yylval.yyint = result;
599                 return result;
600             }
601         }
602         /* Case 4 */
603         else if (c == '-' && next == '>') {
604             return PTR_OP;
605         }
606         /* Case 5 */
607         else {
608             UNGETC(next);
609             return c;
610         }
611         break;
612     }
613     case '{':
614         NestLevel++;
615         return c;
616     case '}':
617         NestLevel--;
618         return c;
619     case '.':
620         c = GETC();
621         if (c == '.') {
622             c = GETC();
623             if (c == '.') {
624                 return VAR_ARGS;
625             }
626         }
627         UNGETC(c);
628         return '.';
629     case '[': case ']':
630         return c;
631     case ',':
632     case ':':
633     case '(': case ')':
634     case '~':
635     case '?':
636     case ';':
637         /* Special characters that cant be part of a composite */
638         return c;
639     default:
640         error("Unhandled character %c", c);
641     }
642     return 0;
643 }
644
645 #define ENTRY(_a)       case (_a): printf(#_a); break;
646
647 int yylex(void)
648 {
649     int ret = _yylex();
650 #if DUMP_OUTPUT
651     static int lastpos = 0;
652     char tmp;
653
654     printf("Returning ");
655     switch (ret) {
656         /* Wrapper */
657         ENTRY(IDENTIFIER);
658         ENTRY(TYPE_NAME);
659         ENTRY(CONSTANT);
660         ENTRY(STRING_LITERAL);
661         ENTRY(SIZEOF);
662         ENTRY(PTR_OP);
663         ENTRY(INC_OP);
664         ENTRY(DEC_OP);
665         ENTRY(LEFT_OP);
666         ENTRY(RIGHT_OP);
667         ENTRY(LE_OP);
668         ENTRY(GE_OP);
669         ENTRY(EQ_OP);
670         ENTRY(NE_OP);
671         ENTRY(AND_OP);
672         ENTRY(OR_OP);
673         ENTRY(MUL_ASSIGN);
674         ENTRY(DIV_ASSIGN);
675         ENTRY(MOD_ASSIGN);
676         ENTRY(ADD_ASSIGN);
677         ENTRY(SUB_ASSIGN);
678         ENTRY(LEFT_ASSIGN);
679         ENTRY(RIGHT_ASSIGN);
680         ENTRY(AND_ASSIGN);
681         ENTRY(XOR_ASSIGN);
682         ENTRY(OR_ASSIGN);
683         ENTRY(TYPEDEF);
684         ENTRY(EXTERN);
685         ENTRY(STATIC);
686         ENTRY(AUTO);
687         ENTRY(REGISTER);
688         ENTRY(CODE);
689         ENTRY(EEPROM);
690         ENTRY(INTERRUPT);
691         ENTRY(SFR);
692         ENTRY(AT);
693         ENTRY(SBIT);
694         ENTRY(REENTRANT);
695         ENTRY(USING);
696         ENTRY(XDATA);
697         ENTRY(DATA);
698         ENTRY(IDATA);
699         ENTRY(PDATA);
700         ENTRY(VAR_ARGS);
701         ENTRY(CRITICAL);
702         ENTRY(NONBANKED);
703         ENTRY(BANKED);
704         ENTRY(CHAR);
705         ENTRY(SHORT);
706         ENTRY(INT);
707         ENTRY(LONG);
708         ENTRY(SIGNED);
709         ENTRY(UNSIGNED);
710         ENTRY(FLOAT);
711         ENTRY(DOUBLE);
712         ENTRY(CONST);
713         ENTRY(VOLATILE);
714         ENTRY(VOID);
715         ENTRY(BIT);
716         ENTRY(STRUCT);
717         ENTRY(UNION);
718         ENTRY(ENUM);
719         ENTRY(ELIPSIS);
720         ENTRY(RANGE);
721         ENTRY(FAR);
722         ENTRY(_XDATA);
723         ENTRY(_CODE);
724         ENTRY(_GENERIC);
725         ENTRY(_NEAR);
726         ENTRY(_PDATA);
727         ENTRY(_IDATA);
728         ENTRY(_EEPROM);
729         ENTRY(CASE);
730         ENTRY(DEFAULT);
731         ENTRY(IF);
732         ENTRY(ELSE);
733         ENTRY(SWITCH);
734         ENTRY(WHILE);
735         ENTRY(DO);
736         ENTRY(FOR);
737         ENTRY(GOTO);
738         ENTRY(CONTINUE);
739         ENTRY(BREAK);
740         ENTRY(RETURN);
741         ENTRY(INLINEASM);
742         ENTRY(IFX);
743         ENTRY(ADDRESS_OF);
744         ENTRY(GET_VALUE_AT_ADDRESS);
745         ENTRY(SPIL);
746         ENTRY(UNSPIL);
747         ENTRY(GETHBIT);
748         ENTRY(BITWISEAND);
749         ENTRY(UNARYMINUS);
750         ENTRY(IPUSH);
751         ENTRY(IPOP);
752         ENTRY(PCALL);
753         ENTRY(ENDFUNCTION);
754         ENTRY(JUMPTABLE);
755         ENTRY(RRC);
756         ENTRY(RLC);
757         ENTRY(CAST);
758         ENTRY(CALL);
759         ENTRY(PARAM);
760         ENTRY(NULLOP);
761         ENTRY(BLOCK);
762         ENTRY(LABEL);
763         ENTRY(RECEIVE);
764         ENTRY(SEND);
765     default:
766         printf("default: %c", ret);
767     }
768     tmp = linebuf[linepos];
769     linebuf[linepos] = '\0';
770     printf(" for %s (%u bytes)\n", linebuf + lastpos, linepos - lastpos);
771     linebuf[linepos] = tmp;
772     lastpos = linepos;
773     fflush(stdout);
774 #endif
775     return ret;
776 }
777
778 #define TEST(_a)        (_a) ? (void)0 : printf("Test %s failed\n", #_a);
779
780 int altlex_testparse(const char *input)
781 {
782     /* Fiddle with the read-ahead buffer to insert ourselves */
783     strcpy(linebuf, input);
784     linelen = strlen(linebuf)+1;
785     linepos = 0;
786     
787     return yylex();
788 }
789
790 int altlex_testchar(const char *input)
791 {
792     value *val;
793     if (altlex_testparse(input) != CONSTANT)
794         return -2;
795     val = yylval.val;
796     if (val->type->class != SPECIFIER)
797         return -3;
798     if (SPEC_NOUN(val->type) != V_CHAR)
799         return -4;
800     if (SPEC_SCLS(val->type) != S_LITERAL)
801         return -5;
802     return SPEC_CVAL(val->type).v_int;
803 }
804
805 int altlex_testnum(const char *input)
806 {
807     value *val;
808     if (altlex_testparse(input) != CONSTANT)
809         return -2;
810     val = yylval.val;
811     if (val->type->class != SPECIFIER)
812         return -3;
813     if (SPEC_NOUN(val->type) != V_INT)
814         return -4;
815     if (SPEC_SCLS(val->type) != S_LITERAL)
816         return -5;
817     if (SPEC_USIGN(val->type))
818         return SPEC_CVAL(val->type).v_uint;
819     else
820         return SPEC_CVAL(val->type).v_int;
821 }
822
823 int altlex_runtests(void)
824 {
825     /* These conditions are ripped directly from SDCC.lex */
826     /* First check the parsing of the basic tokens */
827     TEST(altlex_testparse(">>=") == RIGHT_ASSIGN);
828     TEST(altlex_testparse("<<=") == LEFT_ASSIGN);
829     TEST(altlex_testparse("+=") == ADD_ASSIGN);
830     TEST(altlex_testparse("-=") == SUB_ASSIGN);
831     TEST(altlex_testparse("*=") == MUL_ASSIGN);
832     TEST(altlex_testparse("/=") == DIV_ASSIGN);
833     TEST(altlex_testparse("%=") == MOD_ASSIGN);
834     TEST(altlex_testparse("&=") == AND_ASSIGN);
835     TEST(altlex_testparse("^=") == XOR_ASSIGN);
836     TEST(altlex_testparse("|=") == OR_ASSIGN);
837     TEST(altlex_testparse(">>") == RIGHT_OP);
838     TEST(altlex_testparse("<<") == LEFT_OP);
839     TEST(altlex_testparse("++") == INC_OP);
840     TEST(altlex_testparse("--") == DEC_OP);
841     TEST(altlex_testparse("->") == PTR_OP);
842     TEST(altlex_testparse("&&") == AND_OP);
843     TEST(altlex_testparse("||") == OR_OP);
844     TEST(altlex_testparse("<=") == LE_OP);
845     TEST(altlex_testparse(">=") == GE_OP);
846     TEST(altlex_testparse("==") == EQ_OP);
847     TEST(altlex_testparse("!=") == NE_OP);
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     TEST(altlex_testparse("*") == '*');
865     TEST(altlex_testparse("/") == '/');
866     TEST(altlex_testparse("%") == '%');
867     TEST(altlex_testparse("<") == '<');
868     TEST(altlex_testparse(">") == '>');
869     TEST(altlex_testparse("^") == '^');
870     TEST(altlex_testparse("|") == '|');
871     TEST(altlex_testparse("?") == '?');
872
873     /* Now some character constants */
874     TEST(altlex_testchar("'1'") == '1');
875     TEST(altlex_testchar("'a'") == 'a');
876     TEST(altlex_testchar("'A'") == 'A');
877     TEST(altlex_testchar("'z'") == 'z');
878     TEST(altlex_testchar("'Z'") == 'Z');
879     TEST(altlex_testchar("'\n'") == '\n');
880     TEST(altlex_testchar("'\\\\'") == '\\');
881     TEST(altlex_testchar("'\\''") == '\'');
882
883     /* And some numbers */
884     TEST(altlex_testnum("0") == 0);
885     TEST(altlex_testnum("1") == 1);
886     TEST(altlex_testnum("075") == 075);
887     TEST(altlex_testnum("0xfeed") == 0xfeed);
888     TEST(altlex_testnum("0xFEED") == 0xFEED);
889     TEST(altlex_testnum("0x00005678") == 0x5678);
890
891     /* Keywords */
892     TEST(altlex_testparse("auto") == AUTO);
893     TEST(altlex_testparse("break") == BREAK);
894     TEST(altlex_testparse("case") == CASE);
895     TEST(altlex_testparse("char") == CHAR);
896     TEST(altlex_testparse("const") == CONST);
897     TEST(altlex_testparse("continue") == CONTINUE);
898     TEST(altlex_testparse("default") == DEFAULT);
899     TEST(altlex_testparse("do") == DO);
900     /* Prints a warning */
901     //    TEST(altlex_testparse("double") == FLOAT);
902     TEST(altlex_testparse("else") == ELSE);
903     TEST(altlex_testparse("enum") == ENUM);
904     TEST(altlex_testparse("extern") == EXTERN);
905     TEST(altlex_testparse("float") == FLOAT);
906     TEST(altlex_testparse("for") == FOR);
907     TEST(altlex_testparse("goto") == GOTO);
908     TEST(altlex_testparse("if") == IF);
909     TEST(altlex_testparse("int") == INT);
910     TEST(altlex_testparse("interrupt") == INTERRUPT);
911     TEST(altlex_testparse("long") == LONG);
912     TEST(altlex_testparse("register") == REGISTER);
913     TEST(altlex_testparse("return") == RETURN);
914     TEST(altlex_testparse("short") == SHORT);
915     TEST(altlex_testparse("signed") == SIGNED);
916     TEST(altlex_testparse("sizeof") == SIZEOF);
917     TEST(altlex_testparse("static") == STATIC);
918     TEST(altlex_testparse("struct") == STRUCT);
919     TEST(altlex_testparse("switch") == SWITCH);
920     TEST(altlex_testparse("typedef") == TYPEDEF);
921     TEST(altlex_testparse("union") == UNION);
922     TEST(altlex_testparse("unsigned") == UNSIGNED);
923     TEST(altlex_testparse("void") == VOID);
924     TEST(altlex_testparse("volatile") == VOLATILE);
925     TEST(altlex_testparse("while") == WHILE);
926     TEST(altlex_testparse("...") == VAR_ARGS);
927
928 #if 0
929     /* Platform specific keywords */
930     TEST(altlex_testparse("sram") ==)         { count(); TKEYWORD(XDATA);}
931     TEST(altlex_testparse("using") ==)        { count(); TKEYWORD(USING); }
932     TEST(altlex_testparse("near") ==)          { count(); TKEYWORD(DATA);}
933     TEST(altlex_testparse("at") ==)            { count(); TKEYWORD(AT)  ; }
934     TEST(altlex_testparse("bit") ==)           { count(); TKEYWORD(BIT) ; }
935     TEST(altlex_testparse("code") ==)         { count(); TKEYWORD(CODE); }
936     TEST(altlex_testparse("critical") ==)     { count(); TKEYWORD(CRITICAL); } 
937     TEST(altlex_testparse("data") ==)          { count(); TKEYWORD(DATA);   }
938     TEST(altlex_testparse("far") ==)          { count(); TKEYWORD(XDATA);  }
939     TEST(altlex_testparse("eeprom") ==)       { count(); TKEYWORD(EEPROM);  }
940     TEST(altlex_testparse("flash") ==)        { count(); TKEYWORD(CODE);}
941     TEST(altlex_testparse("idata") ==)        { count(); TKEYWORD(IDATA);}
942     TEST(altlex_testparse("nonbanked") ==)    { count(); TKEYWORD(NONBANKED);}
943     TEST(altlex_testparse("banked") ==)       { count(); TKEYWORD(BANKED);}
944     TEST(altlex_testparse("pdata") ==)        { count(); TKEYWORD(PDATA); }
945     TEST(altlex_testparse("reentrant") ==)    { count(); TKEYWORD(REENTRANT);}
946     TEST(altlex_testparse("sfr") ==)           { count(); TKEYWORD(SFR) ; }
947     TEST(altlex_testparse("sbit") ==)          { count(); TKEYWORD(SBIT)        ; }
948     TEST(altlex_testparse("xdata") ==)        { count(); TKEYWORD(XDATA); }
949     TEST(altlex_testparse("_data") ==)         { count(); TKEYWORD(_NEAR); }
950     TEST(altlex_testparse("_code") ==)         { count(); TKEYWORD(_CODE); }
951     TEST(altlex_testparse("_eeprom") ==)      { count(); TKEYWORD(_EEPROM); }
952     TEST(altlex_testparse("_flash") ==)       { count(); TKEYWORD(_CODE); }
953     TEST(altlex_testparse("_generic") ==)     { count(); TKEYWORD(_GENERIC); }
954     TEST(altlex_testparse("_near") ==)         { count(); TKEYWORD(_NEAR); }
955     TEST(altlex_testparse("_sram") ==)        { count(); TKEYWORD(_XDATA);}
956     TEST(altlex_testparse("_xdata") ==)       { count(); TKEYWORD(_XDATA);}
957     TEST(altlex_testparse("_pdata") ==)       { count(); TKEYWORD(_PDATA); }
958     TEST(altlex_testparse("_idata") ==)       { count(); TKEYWORD(_IDATA); }
959 #endif
960
961     return 0;
962 }