a56: Add manpage by Denis Briand
[linux-libre-firmware.git] / as31 / as31 / lexer.c
1 /* ----------------------------------------------------------------------
2  * FILE: lexer.c
3  * PACKAGE: as31 - 8031/8051 Assembler.
4  *
5  * DESCRIPTION:
6  *      This file contains the lexical tokenizer for the assembler.
7  *      Since yacc is being used the lexer is called yylex().
8  *
9  *      In order to produce a listing, some record of the users
10  *      source line must be kept. This is done by adding
11  *      get_ch(), and unget_ch() routine which returns/ungets a character
12  *      but also places information into a secret array.
13  *
14  *      When a newline is encountered the text line is returned as
15  *      an attribute on the '\n' character.
16  *
17  * REVISION HISTORY:
18  *      Jan. 19, 1990 - Created. (Ken Stauffer)
19  *
20  * AUTHOR:
21  *      All code in this file written by Ken Stauffer (University of Calgary).
22  *      January, 1990.
23  *
24  */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29
30 #include "as31.h"
31 #include "parser.h"
32
33
34 int lineno;
35 int last_token_len=0;
36 char last_token[256], prev_token[256];
37
38 static char line[100];
39 static char *lineptr=line;
40
41 /* ----------------------------------------------------------------------
42  * get_ch:
43  *      Get a character from stdin, place char in line[]
44  */
45
46 int get_ch(void)
47 {
48         register int c;
49
50         c = getchar();
51         if (last_token_len >=0 && last_token_len < 254 &&
52            c != EOF && (last_token_len > 0 || !isspace(c))) {
53                 last_token[last_token_len++] = c;
54         }
55         if( c != EOF && lineptr - line < sizeof(line) )
56                 *lineptr++ = c;
57         return(c);
58 }
59
60 /* ----------------------------------------------------------------------
61  * unget_ch:
62  *      Unget a character and move lineptr back by one.
63  */
64
65 void unget_ch(int c)
66 {
67         ungetc(c,stdin);
68         if( lineptr > line )
69                 lineptr--;
70 }
71
72
73
74 /* when there is a parse error, yyparse should call here to */
75 /* advance to the end of the current line, so we can continue */
76 /* parsing the rest of the file */
77
78 int seek_eol(void)
79 {
80         int c;
81
82         last_token_len = -1;
83         do {
84                 c = get_ch();
85         } while (c != '\n' && c != EOF);
86         if (c == '\n') {
87                 unget_ch(c);
88                 return 1;
89         }
90         return 0;
91 }
92
93 /* return a pointer to the last successfully parsed token, so */
94 /* we can give a nicer error message when there is a syntax error */
95
96 const char *get_last_token(void)
97 {
98         /*
99         if (last_token_len < 0) last_token_len = 0;
100         last_token[last_token_len] = '\0';
101         */
102         return prev_token;
103 }
104
105
106
107 /* ----------------------------------------------------------------------
108  * yylex:
109  *      The tokens themselves are returned via return(token)
110  *
111  *      Some tokens have attributes. These attributes are returned
112  *      by setting a global variable yylval:
113  *
114  *              yylval.value
115  *                      numbers (any base)
116  *                      strings (in pass 1).
117  *                      bit positions .0, .1, .2, ...
118  *
119  *              yylval.str
120  *                      strings (in pass 2).
121  *                      '\n' (both passes).
122  *
123  *              yylval.sym
124  *                      User defined symbols.
125  *
126  *              yylval.op
127  *                      Reserved keyword (opcode/directive/misc.)
128  *
129  *              No other fields in yylval are used by yylex().
130  * 
131  *              Characters that do not have an attribute do
132  *              not set anything in the yylval variable.
133  *
134  */
135
136
137
138 int yylex(void)
139 {
140         static int nl_flag=0;   /* sync. error messages and the cur. line */
141         register int c;
142         char buf[1024];         /* temporary buffer */
143         char *p;                /* general pointer */
144         struct symbol *sym;
145         struct opcode *op;
146
147         int octal=0,hex=0,decimal=0,binary=0;
148         register long value = 0;
149
150         if (last_token_len > 0) {
151                 last_token[last_token_len] = '\0';
152                 strcpy(prev_token, last_token);
153         } else {
154                 *prev_token = '\0';
155         }
156         last_token_len=0;
157
158         if( nl_flag ) {
159                 nl_flag = 0;
160                 lineno++;
161         }
162
163 for(;;) {
164         c = get_ch();
165         switch(c) {
166         case EOF: return(EOF);
167         case ' ':
168         case '\r':
169         case '\t':
170                 break;
171
172         case '\n':
173                 nl_flag = 1;
174                 yylval.str = line;
175                 *lineptr = '\0';
176                 lineptr = line;
177                 return('\n');
178
179         case ';':
180                 while((c=get_ch()) != EOF && c!='\n');
181                 nl_flag= 1;
182                 yylval.str = line;
183                 *lineptr = '\0';
184                 lineptr = line;
185                 return(c);
186
187         case '"':
188                 p = buf;
189                 while((c=get_ch()) != EOF && c!='"' && c!='\n') {
190                         if( c == '\\' ) {
191                                 switch(c=get_ch()) {
192                                 case 'n': c = '\n'; break;
193                                 case 'r': c = '\r'; break;
194                                 case 't': c = '\t'; break;
195                                 case 'b': c = '\b'; break;
196                                 case '"': c = '"'; break;
197                                 case '\\': c = '\\'; break;
198                                 default:
199                                   warn("Invalid escape character: \\%c",c);
200                                 }
201                         }
202                         if( p-buf<sizeof(buf)-1 ) {
203                                 *p++ = c;
204                         } else {
205                            error("String constant longer than %d bytes",
206                                         sizeof(buf));
207                         }
208                 }
209                 *p = '\0';
210                 if( c == '\n' || c == EOF ) {
211                         warn("String terminated improperly");
212                         unget_ch(c);
213                 }
214
215                 if (pass1) {
216                         yylval.value = strlen(buf);
217                 } else {
218                         p = (char *)malloc(strlen(buf) + 1);
219                         if (p == NULL) {
220                                 error("Cannot allocate %d bytes",
221                                         strlen(buf) + 1);
222                                 yylval.str = "as31 ran out of memory!";
223                                 return(STRING);
224                         }
225                         strcpy(p, buf);
226                         yylval.str = p;
227                 }
228                 return(STRING);
229
230         case '.':
231                 if( (c=get_ch())>='0' && c<='7' ) {
232                         yylval.value = c-'0';
233                         return(BITPOS);
234                 }
235                 unget_ch(c);
236                 return('.');
237
238         case '\'':
239                 c = get_ch();
240                 if( c=='\\' ) {
241                         switch(c=get_ch()) {
242                         case 'n': c = '\n'; break;
243                         case 'r': c = '\r'; break;
244                         case 't': c = '\t'; break;
245                         case 'b': c = '\b'; break;
246                         case '0': c = 0; break;
247                         case 'o': c = 0; break;
248                         case 'O': c = 0; break;
249                         case '\\': c = '\\'; break;
250                         case '\'': c = '\''; break;
251                         default:
252                                 warn("Invalid escape character: \\%c",c);
253                         }
254                 }
255                 if( get_ch() != '\'' )
256                         warn("Missing quote in character constant");
257                 yylval.value = c;
258                 return(VALUE);
259
260         case '0':       /* parse a number                       */
261         case '1':       /* could be followed by a:              */
262         case '2':       /*      'b','B' - Binary                */
263         case '3':       /*      'h','H' - Hex                   */
264         case '4':       /*      'd','D' - Decimal               */
265         case '5':       /*      'o','O' - Octal                 */
266         case '6':       /* *** Numbers must start with a digit  */
267         case '7':       /* Numbers could be also preceeded by:  */
268         case '8':       /*      0x      - Hex                   */
269         case '9':       /*      0b      - binary                */
270
271                 p = buf;
272                 do {
273                         if( p-buf<sizeof(buf)-1 )
274                                 *p++ = c;
275                         c = get_ch();
276                 } while( c=='H' || c=='h' || c=='O' || c=='o' ||
277                                 c=='x' || c=='X' || isxdigit(c) );
278                 unget_ch(c);
279                 *p = '\0';
280
281                 /* Check any preceeding chars */
282                 if( buf[0]=='0' && (buf[1]=='x' || buf[1]=='X') ) {
283                                 hex++;
284                                 buf[1] = '0';
285                 } else {
286                         if( buf[0]=='0' &&
287                           (buf[1]=='b' || buf[1]=='B') &&
288                           *(p-1) != 'h' && *(p-1) != 'H') {
289                                 binary++;
290                                 buf[1] = '0';
291                         }
292                 }
293
294                 /* check any trailing chars */
295                 c = *(p-1);
296                 if( !hex && (c=='b' || c=='B') )
297                         { binary++; *(p-1) = '\0'; }
298                 else if( c=='H' || c=='h' )
299                         { hex++; *(p-1) = '\0'; }
300                 else if( !hex && (c=='D' || c=='d') )
301                         { decimal++; *(p-1) = '\0'; }
302                 else if( c=='O' || c=='o' )
303                         { octal++; *(p-1) = '\0'; }
304                 else if( !hex && !octal && !binary) decimal++;
305
306                 if (binary) {
307                         if (hex) warn("ambiguous number, bin or hex");
308                         if (decimal) warn("ambiguous number, bin or dec");
309                         if (octal) warn("ambiguous number, bin or oct");
310                         for(p=buf; *p; p++ ) {
311                                 if( *p=='1' ) value = value * 2 + 1;
312                                 else if( *p=='0' ) value = value * 2;
313                                 else
314                                   warn("Invalid binary digit: %c",*p);
315                         }
316                         yylval.value = value;
317                         return(VALUE);
318                 }
319
320                 if (hex) {
321                         if (binary) warn("ambiguous number, hex or bin");
322                         if (decimal) warn("ambiguous number, hex or dec");
323                         if (octal) warn("ambiguous number, hex or oct");
324                         for(p=buf; *p; p++ ) {
325                                 value <<= 4;
326                                 if( isdigit(*p) )
327                                         value += *p-'0';
328                                 else if( *p>='a' && *p<='f' )
329                                         value += *p-'a'+ 10;
330                                 else if( *p>='A' && *p<='F' )
331                                         value += *p-'A'+ 10;
332                                 else
333                                   warn("Invalid hex digit: %c",*p);
334                         }
335                         yylval.value = value;
336                         return(VALUE);
337                 }
338
339                 if (decimal) {
340                         if (hex) warn("ambiguous number, dec or hex");
341                         if (binary) warn("ambiguous number, dec or bin");
342                         if (octal) warn("ambiguous number, dec or oct");
343                         for(p=buf; *p; p++ ) {
344                                 if( isdigit(*p) )
345                                         value = value*10 + *p-'0';
346                                 else
347                                    warn("Invalid decimal digit: %c",*p);
348                         }
349                         yylval.value = value;
350                         return(VALUE);
351                 }
352
353                 if (octal) {
354                         if (hex) warn("ambiguous number, oct or hex");
355                         if (binary) warn("ambiguous number, oct or bin");
356                         if (decimal) warn("ambiguous number, oct or dec");
357                         for(p=buf; *p; p++ ) {
358                                 if( *p>='0' && *p<='7' )
359                                         value = (value << 3) + (*p - '0');
360                                 else
361                                    warn("Invalid octal digit: %c",*p);
362                         }
363                         yylval.value = value;
364                         return(VALUE);
365                 }
366
367         default:
368                 if( isalpha(c) || c=='_' ) {
369                         p = buf;
370                         do {
371                                 if( p-buf<sizeof(buf)-1 )
372                                         *p++ = c;
373                                 c = get_ch();
374                         } while( isalnum(c) || c=='_' );
375                         *p = '\0';
376                         unget_ch(c);
377                         if ( (op = lookop(buf)) != NULL ) {
378                                 yylval.op = op;
379                                 return(op->type);
380                         }
381                         sym = looksym(buf);
382                         yylval.sym = sym;
383                         return(SYMBOL);
384                 } else
385                         return(c);
386         } /* switch */
387 } /* for */
388
389 } /* yylex */
390
391