1 /* vim:set shiftwidth=4 ts=8: */
2
3 %{
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <ctype.h>
8
9 typedef struct _term term_t;
10 struct _term {
11 int kind;
12 union {
13 char c;
14 char* s;
15 term_t* t;
16 } u;
17 term_t* next;
18 };
19
20 static FILE* outf;
21 static int yylex ();
22 static void yyerror (char*);
23 static void xlate (term_t* ts);
24
25 static void
nonTerm(char * s)26 nonTerm (char* s)
27 {
28 fprintf (outf, "<I>%s</I>", s);
29 }
30
31 static void
gen(char * name,term_t * ts)32 gen (char* name, term_t* ts)
33 {
34 fprintf (outf, "<TR>\n <TD ALIGN=RIGHT>");
35 nonTerm (name);
36 fprintf (outf, "</TD>\n <TD ALIGN=LEFT>:</TD>\n <TD ALIGN=LEFT>");
37 xlate (ts);
38 fprintf (outf, "</TD>\n</TR>\n");
39
40 for (ts = ts->next; ts; ts = ts->next) {
41 fprintf (outf, "<TR>\n <TD ALIGN=RIGHT></TD>\n <TD ALIGN=LEFT>|</TD>\n <TD ALIGN=LEFT>");
42 xlate (ts);
43 fprintf (outf, "</TD>\n</TR>\n");
44 }
45 }
46
47 static term_t*
mkLiteral(char c,int kind)48 mkLiteral (char c, int kind)
49 {
50 term_t* nt = (term_t*)malloc(sizeof(term_t));
51 nt->kind = kind;
52 nt->u.c = c;
53 nt->next = 0;
54 return nt;
55 }
56
57 static term_t*
mkID(char * s,int kind)58 mkID (char* s, int kind)
59 {
60 term_t* nt = (term_t*)malloc(sizeof(term_t));
61 nt->kind = kind;
62 nt->u.s = s;
63 nt->next = 0;
64 return nt;
65 }
66
67 static term_t*
mkSeq(term_t * t1,term_t * t2,int kind)68 mkSeq (term_t* t1, term_t* t2, int kind)
69 {
70 term_t* nt = (term_t*)malloc(sizeof(term_t));
71 nt->kind = kind;
72 nt->u.t = t1;
73 t1->next = t2;
74 nt->next = 0;
75 return nt;
76 }
77
78 static term_t*
mkTerm(term_t * t,int kind)79 mkTerm (term_t* t, int kind)
80 {
81 term_t* nt = (term_t*)malloc(sizeof(term_t));
82 nt->kind = kind;
83 nt->u.t = t;
84 nt->next = 0;
85 return nt;
86 }
87
88 %}
89
90 %union {
91 char c;
92 char* str;
93 term_t* term;
94 }
95
96 %token <c> T_literal
97 %token <str> T_name T_token T_opt T_seq T_choice
98 %type <term> atomterm term rule rulelist
99 %start prods
100
101 %%
102
103 prods : prods prod
104 | prod
105 ;
106
107 prod : T_name '=' rulelist '\n'
108 { gen ($1, $3); }
109
110 rulelist : rule '|' rulelist { $1->next = $3; $$ = $1; }
111 | rule { $$ = $1; }
112 ;
113
114 rule : term rule
115 { if ($2->kind == T_seq) { $1->next = $2->u.t; $2->u.t = $1; $$ = $2;}
116 else $$ = mkSeq ($1, $2, T_seq); }
117 | term { $$ = $1; }
118 ;
119
120 term : '[' rule ']' { $$ = mkTerm ($2, T_opt); }
121 | '(' rulelist ')' { $$ = mkTerm ($2, T_choice); }
122 | atomterm { $$ = $1; }
123 ;
124
125 atomterm : T_literal { $$ = mkLiteral($1, T_literal); }
126 | T_token { $$ = mkID($1, T_token); }
127 | T_name { $$ = mkID($1, T_name); }
128 ;
129
130 %%
131
132 static void
133 xlate (term_t* ts)
134 {
135 term_t* t;
136
137 switch (ts->kind) {
138 case T_name :
139 nonTerm (ts->u.s);
140 break;
141 case T_literal :
142 fprintf (outf, "<B>'%c'</B>", ts->u.c);
143 break;
144 case T_token :
145 fprintf (outf, "<B>%s</B>", ts->u.s);
146 break;
147 case T_opt :
148 fprintf (outf, "[ ");
149 xlate (ts->u.t);
150 fprintf (outf, " ]");
151 break;
152 case T_seq :
153 t = ts->u.t;
154 xlate (t);
155 for (t = t->next; t; t = t->next) {
156 fprintf (outf, " ");
157 xlate (t);
158 }
159 break;
160 case T_choice :
161 fprintf (outf, "(");
162 t = ts->u.t;
163 xlate (t);
164 for (t = t->next; t; t = t->next) {
165 fprintf (outf, " | ");
166 xlate (t);
167 }
168 fprintf (outf, ")");
169 break;
170 }
171 }
172
173 #define BSIZE 2048
174
175 static FILE* inf;
176 static char buf[BSIZE];
177 static char* lexptr;
178 static int lineno;
179
180 static char*
skipSpace(char * p)181 skipSpace (char* p)
182 {
183 int c;
184 while (isspace ((c = *p)) && (c != '\n')) p++;
185 return p;
186 }
187
188 static char*
mystrndup(char * p,int sz)189 mystrndup (char* p, int sz)
190 {
191 char* s = malloc (sz+1);
192 memcpy (s, p, sz);
193 s[sz] = '\0';
194 return s;
195 }
196
197 static char*
readLiteral(char * p)198 readLiteral (char* p)
199 {
200 int c;
201 char* s = p;
202
203 while (((c = *p) != '\'') && (c != '\0')) p++;
204 if (c == '\0') {
205 fprintf (stderr, "Unclosed literal '%s, line %d\n", s, lineno);
206 exit (1);
207 }
208 yylval.c = *s;
209 return (p+1);
210 }
211
212 static char*
readName(char * p)213 readName (char* p)
214 {
215 int c;
216 char* s = p;
217
218 while (!isspace ((c = *p)) && (c != '\0')) p++;
219 yylval.str = mystrndup (s, p-s);
220 return p;
221 }
222
223 static void
yyerror(char * msg)224 yyerror (char* msg)
225 {
226 fprintf (stderr, "%s, line %d\n", msg, lineno);
227 }
228
229 static void
lexinit()230 lexinit ()
231 {
232 lexptr = buf;
233 }
234
235 #ifdef DEBUG
236 static int _yylex ();
yylex()237 int yylex()
238 { /* for debugging */
239 int rv = _yylex();
240 fprintf(stderr, "returning %d\n", rv);
241 switch (rv) {
242 case T_name :
243 case T_token :
244 fprintf(stderr, "string val is '%s'\n", yylval.str);
245 break;
246 case T_literal :
247 fprintf(stderr, "string val is '%c'\n", yylval.c);
248 break;
249 }
250 return rv;
251 }
252 #define yylex _yylex
253 #endif
254
255 static int
yylex()256 yylex ()
257 {
258 int c;
259 do {
260 if (*lexptr == '\0') {
261 if (!fgets (buf, BSIZE, inf)) return EOF;
262 lineno++;
263 lexptr = buf;
264 }
265 lexptr = skipSpace (lexptr);
266 } while (*lexptr == '\0');
267
268 switch (c = *lexptr++) {
269 case '\n' :
270 case '|' :
271 case '=' :
272 case '(' :
273 case ')' :
274 case '[' :
275 case ']' :
276 return c;
277 break;
278 case '\'' :
279 lexptr = readLiteral (lexptr);
280 return T_literal;
281 break;
282 case 'T' :
283 if (*lexptr == '_') {
284 lexptr = readName (lexptr+1);
285 return T_token;
286 }
287 else {
288 lexptr = readName (lexptr-1);
289 return T_name;
290 }
291 break;
292 default :
293 lexptr = readName (lexptr-1);
294 return T_name;
295 break;
296 }
297 }
298 #ifdef DEBUG
299 #undef yylex
300 #endif
301
302 static FILE*
openF(char * fname,char * mode)303 openF (char* fname, char* mode)
304 {
305 FILE* f = fopen (fname, mode);
306
307 if (!f) {
308 fprintf (stderr, "Could not open %s for %s\n", fname, mode);
309 exit(1);
310 }
311 return f;
312 }
313
314 int
main(int argc,char * argv[])315 main (int argc, char* argv[])
316 {
317 if (argc != 3) {
318 fprintf (stderr, "mklang: 2 arguments required\n");
319 exit(1);
320 }
321 inf = openF (argv[1], "r");
322 outf = openF (argv[2], "w");
323 lexinit();
324 yyparse ();
325 return (0);
326 }
327