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