INTERCAL 0.13 release.
[intercal:intercal.git] / src / lexer.l
1 %{
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <ctype.h>
5 #include <string.h>
6 #include <memory.h>
7 #include "ick.h"
8 #include "y.tab.h"
9 #include "lose.h"
10
11 #define YY_NO_UNPUT
12
13 #ifndef yywrap
14 static int yywrap(void)
15 {
16     return 1;
17 }
18 #endif /* yywrap */
19
20 #ifdef YYLINENO_BY_HAND
21 int     yylineno = 1;
22 #endif /* YYLINENO_BY_HAND */
23
24 #ifdef MAIN
25 YYSTYPE yylval;
26 #endif /* MAIN */
27
28 char *textlines[MAXLINES];
29 int politesse = 0;
30
31 #ifdef FLEX_SCANNER
32 static char linebuf[YY_BUF_SIZE];
33 #else /* FLEX_SCANNER */
34 static char linebuf[YYLMAX];
35 #endif /* FLEX_SCANNER */
36
37 static char *lineptr = linebuf;
38
39 bool re_send_token = FALSE;
40
41 int lexer(void);
42 static int myatoi(char *text);
43         
44 /*
45  * The spectacular ugliness of INTERCAL syntax requires that the lexical
46  * analyzer have two levels. One, embedded in the getc() function, handles
47  * logical-line continuation and the ! abbrev, and stashes each logical
48  * line away in a buffer accessible to the code generator (this is necessary
49  * for the * construct to be interpreted correctly). The upper level is
50  * generated by lex(1) and does normal tokenizing.
51  */
52
53 #undef getc
54 int getc(FILE *fp)
55 {
56     extern FILE* yyin;
57
58     static bool bangflag = FALSE;
59     static bool backflag = FALSE;
60
61     if (bangflag)
62     {
63         bangflag = FALSE;
64         /*      *lineptr++ = '!'; */
65         return('.');
66     }
67     else if (backflag)  /* converting ctrl-H (backspace) to two chars "^H" */
68     {
69         backflag = FALSE;
70         /*      *lineptr++ = '\010'; */
71         return('H');
72     }
73     else
74     {
75         int c = fgetc(fp);
76
77         if (feof(yyin))
78         {
79             *lineptr = '\0';
80             return(EOF);
81         }
82 #ifdef BACKSLASH_CONTINUATION
83         else if (c == '\\')
84         {
85             do {
86                 c = fgetc(fp);
87 #ifdef  YYLINENO_BY_HAND
88                 if( c == '\n' ) yylineno++;
89 #endif  /* YYLINENO_BY_HAND */
90             } while
91                 (c != '\\' && isspace(c));
92         }
93 #endif  /* BACKSLASH_CONTINUATION */
94         if (c == '!')
95         {
96             *lineptr++ = '!';
97             bangflag = TRUE;
98             return(c = '\'');
99         }
100         else if (c == '\010')   /* convert ctrl-H (backspace) to
101                                    two chars "^" and "H" so lex can take it */
102         {
103             *lineptr++ = '\010';
104             backflag = TRUE;
105             return(c = '^');
106         }
107         else if (c == '\n')
108         {
109             *lineptr = '\0';
110             lineptr = linebuf;
111             textlines[yylineno] = strcpy((char *)malloc(1+strlen(linebuf)),linebuf);
112 #ifdef YYLINENO_BY_HAND
113             yylineno++;
114 #endif /* YYLINENO_BY_HAND */
115             return('\n');
116         }
117         else
118         {
119 #ifdef ACCEPT_LOWERCASE
120             if (islower(c))
121                 c = toupper(c);
122 #endif /* ACCEPT_LOWERCASE */
123             return(*lineptr++ = c);
124         }
125     }
126 }
127
128 /* replace YY_INPUT so that it uses our getc function. */
129 #undef YY_INPUT
130 #define YY_INPUT(buf,result,max_size) \
131         { \
132           int c = getc(yyin); \
133           if (c == EOF) { \
134             if (ferror(yyin)) \
135               YY_FATAL_ERROR("input in flex scanner failed"); \
136             result = YY_NULL; \
137           } else { \
138             buf[0] = c; \
139             result = 1; \
140           } \
141         }
142
143 %}
144
145 W       [\ \t\n]*
146 D       [0-9][\ \t\n0-9]*
147
148 %%
149
150 {D}             {yylval.numval = myatoi(yytext); return(NUMBER);}
151 \.              {return(ONESPOT);}
152 \:              {return(TWOSPOT);}
153 \,              {return(TAIL);}
154 \;              {return(HYBRID);}
155 \#              {return(MESH);}
156
157 "C^H/"  |
158 \$              {return(MINGLE);}
159 \~              {return(SELECT);}
160
161 \&              {yylval.numval = AND; return(UNARY);}
162 V               {yylval.numval = OR; return(UNARY);}
163 "V^H-"          |
164 \?              {yylval.numval = XOR; return(UNARY);}
165 \^              {yylval.numval = FIN; return(UNARY);}
166 @               {yylval.numval = WHIRL; return(UNARY);}
167 [2-5]{W}@       {yylval.numval = WHIRL + myatoi(yytext) - 1; return(UNARY);}
168
169 \'              {return(SPARK);}
170 \"              {return(EARS);}
171
172 \({W}{D}\)      {yylval.numval = myatoi(yytext); return(LABEL);}
173
174 DO              {return(DO);}
175 PLEASE          {politesse++; return(DO);}
176 DO{W}PLEASE     {politesse++; return(DO);}
177 PLEASE{W}DO     {politesse++; return(DO);}
178 NOT             {return(NOT);}
179 N\'T            {return(NOT);}
180
181 \%{W}{D}        {yylval.numval = myatoi(yytext);
182                  if (yylval.numval && yylval.numval < 100)
183                    return(OHOHSEVEN);
184                  else
185                    lose(E017, yylineno, (char *)NULL);}
186 SUB             {return(SUB);}
187 BY              {return(BY);}
188
189 \<-             {return(GETS);}
190 CALCULATING     {yylval.numval = GETS; return(GERUND);}
191
192 NEXT            {return(NEXT);}
193 NEXTING         {yylval.numval = NEXT; return(GERUND);}
194 FORGET          {return(FORGET);}
195 FORGETTING      {yylval.numval = FORGET; return(GERUND);}
196 RESUME          {return(RESUME);}
197 RESUMING        {yylval.numval = RESUME; return(GERUND);}
198 STASH           {return(STASH);}
199 STASHING        {yylval.numval = STASH; return(GERUND);}
200 RETRIEVE        {return(RETRIEVE);}
201 RETRIEVING      {yylval.numval = RETRIEVE; return(GERUND);}
202 IGNORE          {return(IGNORE);}
203 IGNORING        {yylval.numval = IGNORE; return(GERUND);}
204 REMEMBER        {return(REMEMBER);}
205 REMEMBERING     {yylval.numval = REMEMBER; return(GERUND);}
206 ABSTAIN{W}FROM  {return(ABSTAIN);}
207 ABSTAINING      {yylval.numval = ABSTAIN; return(GERUND);}
208 REINSTATE       {return(REINSTATE);}
209 REINSTATING     {yylval.numval = REINSTATE; return(GERUND);}
210 READ{W}OUT      {return(READ_OUT);}
211 READING{W}OUT   {yylval.numval = READ_OUT; return(GERUND);}
212 WRITE{W}IN      {return(WRITE_IN);}
213 WRITING{W}IN    {yylval.numval = WRITE_IN; return(GERUND);}
214 COME{W}FROM     {return(COME_FROM);}
215 COMING{W}FROM   {yylval.numval = COME_FROM; return(GERUND);}
216 GIVE{W}UP       {return(GIVE_UP);}
217
218 \+              {return(INTERSECTION);}
219
220 {W}             ;
221 .               {yylval.numval = yytext[0]; return(BADCHAR);}
222
223
224 %%
225
226 int lexer(void)
227 {
228     static int tok = BADCHAR;
229
230     if (re_send_token)
231         re_send_token = FALSE;
232     else 
233     {
234         tok = yylex();
235 #ifdef YYDEBUG
236         if (yydebug)
237             (void) fprintf(stdout, "yylex: returning token %d\n", tok); 
238 #endif /* YYDEBUG */
239     }
240
241 #ifdef YYDEBUG
242     if (yydebug)
243         (void) fprintf(stdout, "lexer: returning token %d\n", tok); 
244 #endif /* YYDEBUG */
245     return(tok);
246 }
247
248 static int myatoi(char *text)
249 {
250 #define MAXTEXT 100
251     static char buf[MAXTEXT];
252     register int i;
253
254     for(buf[i = 0] = '\0';*text && i < MAXTEXT;text++) {
255         if(isdigit(*text)) {
256             buf[i++] = *text;
257         }
258     }
259     buf[i] = '\0';
260     return atoi(buf);
261 }
262
263 void yyerror(char *errtype)
264 {
265 #ifdef MAIN
266     (void) printf("lextest: lexer error: %s.\n", errtype);
267 #else /* MAIN */
268     /* lose(E017, yylineno, (char *)NULL); */
269     (void) errtype;
270 #endif /* MAIN */
271 }
272
273 #ifdef MAIN
274 int main(void)
275 {
276         int     t;
277
278         while ((t = yylex()) > 0)
279         {
280                 (void) printf("%03d %09d\n", t, yylval.numval);
281                 yylval.numval = 0;
282         }
283         return 0;
284 }
285 #endif /* MAIN */