includes.
[swftools.git] / src / parser.lex
1 %{
2
3 #include <string.h>
4 #include "q.h"
5 #include "parser.h"
6
7 //RVALUE         {NUMBER}|{PERCENT}|{NAME}|\"{STRING}\"|{DIM}
8 //<a>.                {printf("<a>%s\n", yytext);}
9 // %x: exclusive, %s: inclusive
10 char*type_names[] = {"twip","number","command","string","assignment","identifier","label","end"};
11 static int line=1;
12 static int column=1;
13
14 mem_t strings;
15 mem_t tokens;
16
17 static void count(char*text, int len, int condition)
18 {
19     int t;
20     for(t=0;t<len;t++) {
21         if(text[t]=='\n') {
22             line++;
23             column=1;
24         } else {
25             column++;
26         }
27     }
28 }
29
30 static char*prefix = 0;
31
32 static void unescapeString(string_t * tmp)
33 {
34     char *p, *p1;
35     /* fixme - this routine expects the string to be
36        null-terminated */
37
38     for (p1=tmp->str; (p=strchr(p1, '\\')); p1 = p+1) 
39     {
40         switch(p[1])
41         {
42             case '\\': p[1] = '\\'; tmp->len--; break;
43             case '"': p[1] = '"'; tmp->len--; break;
44             case 'b': p[1] = '\b'; tmp->len--; break;
45             case 'f': p[1] = '\f'; tmp->len--; break;
46             case 'n': p[1] = '\n'; tmp->len--; break;
47             case 'r': p[1] = '\r'; tmp->len--; break;
48             case 't': p[1] = '\t'; tmp->len--; break;
49             default:
50                 continue;
51         }
52         strcpy(p, p+1);
53     }
54 }
55
56 static void store(enum type_t type, int line, int column, char*text, int length)
57 {
58     struct token_t token;
59     string_t tmp;
60     token.type = type;
61     token.line = line;
62     token.column = column;
63     //printf("->%d(%s) %s\n", type, type_names[type], text);fflush(stdout);
64
65     token.text = 0;
66     switch(type) {
67         case END:
68             string_set2(&tmp, "", 0);
69             token.text = (char*)mem_putstring(&strings, tmp);
70         break;
71         case STRING:
72             string_set2(&tmp, text+1, length-2);
73             unescapeString(&tmp);
74             token.text = (char*)mem_putstring(&strings, tmp);
75         break;
76         case TWIP: 
77         case NUMBER: 
78         case IDENTIFIER:
79             string_set2(&tmp, text, length);
80             if(prefix) {
81                 //strcat
82                 token.text = (char*)mem_put(&strings, prefix, strlen(prefix));
83                 mem_putstring(&strings, tmp);
84             } else {
85                 token.text = (char*)mem_putstring(&strings, tmp);
86             }
87             prefix = 0;
88         break;
89         case LABEL:
90             string_set2(&tmp, text, length-1);
91             token.text = (char*)mem_putstring(&strings, tmp);
92         break;
93         case COMMAND:
94             string_set2(&tmp, text+1, length-1);
95             token.text = (char*)mem_putstring(&strings, tmp);
96         break;
97         case ASSIGNMENT: {
98             char*x = &text[length-1];
99             if(x[-1] == '-' || x[-1] == '+')
100                 x--;
101             do{x--;} while(*x==32 || *x==10 || *x==13 || *x=='\t');
102             x++; //first space
103             string_set2(&tmp, text, x-text);
104             token.text = (char*)mem_putstring(&strings, tmp);
105             /*char*y,*x = strchr(text, '=');
106             if(!x) exit(1);
107             y=x;
108             do{y--;} while(*y==32 || *y==10 || *y==13 || *y=='\t');
109             do{x++;} while(*x==32 || *x==10 || *x==13 || *x=='\t');
110             token.text1 = (char*)put(&strings, text, y-text + 1, 1);
111             token.text2 = (char*)put(&strings, x, length-(x-text), 1);*/
112         } break;
113     }
114
115     mem_put(&tokens, &token, sizeof(struct token_t));
116     prefix = 0;
117 }
118
119 #define MAX_INCLUDE_DEPTH 16
120 YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
121 int include_stack_ptr = 0;
122
123 void handleInclude(char*text, int len)
124 {
125     text+=9;len-=9;
126     while(len >=1 && (text[0] == ' ' || text[0] == '\t')) {
127         text++;len--;
128     }
129     while(len >= 1 && (text[len-1] == ' ' || text[len-1] == '\n')) {
130         len--;
131     }
132     if(len >= 2 && text[0] == '"' && text[len-1] == '"') {
133         text++; len-=2;
134     }
135     text[len] = 0;
136     if(include_stack_ptr >= MAX_INCLUDE_DEPTH) {
137         fprintf( stderr, "Includes nested too deeply" );
138         exit( 1 );
139     }
140     include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
141     yyin = fopen(text, "rb");
142     if (!yyin) {
143         fprintf(stderr, "Couldn't open %s\n", text);
144         exit(1);
145     }
146     yy_switch_to_buffer(
147         yy_create_buffer( yyin, YY_BUF_SIZE ) );
148     BEGIN(INITIAL);
149 }
150
151 #define c() {count(yytext, yyleng, YY_START);}
152 #define s(type) {store(type, line, column, yytext, yyleng);}
153 %}
154
155 %s R
156 %x BINARY
157
158 NAME     [a-zA-Z_./](-*[a-zA-Z0-9_./])*
159 TWIP     ([0-9]+(\.([0-9]([05])?)?)?)
160 NUMBER   [0-9]+(\.[0-9]*)?
161 PERCENT  {NUMBER}%
162 STRING   (\\.|[^\\"\n])*
163 S        [ \n\r\t]
164 RVALUE   \"{STRING}\"|([^ \n\r\t]+)
165
166 %%
167
168 <BINARY>\] {c();BEGIN(0);}
169 <BINARY>.  {c();}
170 <BINARY>\n {c();}
171 {TWIP}/[ \n\r\t]            {s(TWIP);c();BEGIN(0);}
172 {NUMBER}/[ \n\r\t]          {s(NUMBER);c();BEGIN(0);}
173 ^#[^\n]*\n                  {c();}
174 [ \t\r]#[^\n]*\n            {c();}
175 \"{STRING}\"                {s(STRING);c();BEGIN(0);}
176 \"{STRING}$                 {c();printf("unterminated string in line %d: %s\n", line, yytext);exit(1);yyterminate();}
177 {NAME}{S}*\+=               {s(ASSIGNMENT);prefix="<plus>";c();BEGIN(R);}
178 {NAME}{S}*-=                {s(ASSIGNMENT);prefix="<minus>";c();BEGIN(R);}
179 {NAME}{S}*=                 {s(ASSIGNMENT);c();BEGIN(R);}
180 <R>{ /* values which appear only on the right-hand side of assignments, like: x=50% */
181     [^ \n\t\r]*             {s(IDENTIFIER);c();BEGIN(0);}
182 }
183 \.include{S}.*\n                    {handleInclude(yytext, yyleng);}
184 \.{NAME}                    {s(COMMAND);c();}
185 {NAME}{S}*:                 {s(LABEL);c();}
186 {NAME}                      {s(IDENTIFIER);c();}
187 "["                         {c();BEGIN(BINARY);}
188 {S}                         {c();}
189 .                           {char c,c1=yytext[0];
190                              printf("Syntax error in line %d, %d: %s", line, column, yytext);
191                              while(1) {
192                                  c=input();
193                                  if(c=='\n' || c==EOF) 
194                                      break;
195                                 printf("%c", c);
196                              }
197                              if(c1>='0' && c1<='9')
198                                  printf(" (identifiers must not start with a digit)");
199                              printf("\n");
200                              exit(1);
201                              yyterminate();
202                             }
203 <<EOF>>                     {c();
204                              if ( --include_stack_ptr < 0 ) {
205                                 s(END);
206                                 yyterminate();
207                              } else {
208                                  yy_delete_buffer( YY_CURRENT_BUFFER );
209                                  yy_switch_to_buffer(
210                                       include_stack[include_stack_ptr] );
211                              }
212                             }
213
214 %%
215
216 int yywrap()
217 {
218     return 1;
219 }
220
221 void freeTokens(struct token_t*file)
222 {
223     mem_clear(&strings);
224     mem_clear(&tokens);
225 }
226
227 struct token_t* generateTokens(char*filename)
228 {
229     FILE*fi = fopen(filename, "rb");
230     int t;
231     struct token_t*result;
232     int num;
233     if(!fi) {
234         printf("Couldn't find file %s\n", filename);
235         return 0;
236     }
237     yyin = fi;
238
239     mem_init(&strings);
240     mem_init(&tokens);
241     mem_put(&strings, &t, 1); //hack- make all valid strings start at position >0
242
243     line=1;
244     column=1;
245
246     yylex();
247     yy_delete_buffer(yy_current_buffer);
248
249     result = (struct token_t*)tokens.buffer;
250     num = tokens.pos/sizeof(struct token_t);
251
252     for(t=0;t<tokens.pos/sizeof(struct token_t);t++) {
253         if(result[t].text)
254             result[t].text += (int)strings.buffer;
255     }
256
257     fclose(fi);
258     return result;
259 }
260