Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
%{
2
#include "hoc.h"
3
#define	code2(c1,c2)	code(c1); code(c2)
4
#define	code3(c1,c2,c3)	code(c1); code(c2); code(c3)
5
%}
6
%union {
7
	Symbol	*sym;	/* symbol table pointer */
8
	Inst	*inst;	/* machine instruction */
9
	int	narg;	/* number of arguments */
10
	Formal	*formals;	/* list of formal parameters */
11
}
12
%token	<sym>	NUMBER STRING PRINT VAR BLTIN UNDEF WHILE FOR IF ELSE
13
%token	<sym>	FUNCTION PROCEDURE RETURN FUNC PROC READ
14
%type	<formals>	formals
15
%type	<inst>	expr stmt asgn prlist stmtlist
16
%type	<inst>	cond while for if begin end 
17
%type	<sym>	procname
18
%type	<narg>	arglist
19
%right	'=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ
20
%left	OR
21
%left	AND
22
%left	GT GE LT LE EQ NE
23
%left	'+' '-'
24
%left	'*' '/' '%'
25
%left	UNARYMINUS NOT INC DEC
26
%right	'^'
27
%%
28
list:	  /* nothing */
29
	| list '\n'
30
	| list defn '\n'
31
	| list asgn '\n'  { code2(xpop, STOP); return 1; }
32
	| list stmt '\n'  { code(STOP); return 1; } 
33
	| list expr '\n'  { code2(printtop, STOP); return 1; }
34
	| list error '\n' { yyerrok; }
35
	;
36
asgn:	  VAR '=' expr { code3(varpush,(Inst)$1,assign); $$=$3; }
37
	| VAR ADDEQ expr	{ code3(varpush,(Inst)$1,addeq); $$=$3; }
38
	| VAR SUBEQ expr	{ code3(varpush,(Inst)$1,subeq); $$=$3; }
39
	| VAR MULEQ expr	{ code3(varpush,(Inst)$1,muleq); $$=$3; }
40
	| VAR DIVEQ expr	{ code3(varpush,(Inst)$1,diveq); $$=$3; }
41
	| VAR MODEQ expr	{ code3(varpush,(Inst)$1,modeq); $$=$3; }
42
	;
43
stmt:	  expr	{ code(xpop); }
44
	| RETURN { defnonly("return"); code(procret); }
45
	| RETURN expr
46
	        { defnonly("return"); $$=$2; code(funcret); }
47
	| PROCEDURE begin '(' arglist ')'
48
		{ $$ = $2; code3(call, (Inst)$1, (Inst)$4); }
49
	| PRINT prlist	{ $$ = $2; }
50
	| while '(' cond ')' stmt end {
51
		($1)[1] = (Inst)$5;	/* body of loop */
52
		($1)[2] = (Inst)$6; }	/* end, if cond fails */
53
	| for '(' cond ';' cond ';' cond ')' stmt end {
54
		($1)[1] = (Inst)$5;	/* condition */
55
		($1)[2] = (Inst)$7;	/* post loop */
56
		($1)[3] = (Inst)$9;	/* body of loop */
57
		($1)[4] = (Inst)$10; }	/* end, if cond fails */
58
	| if '(' cond ')' stmt end {	/* else-less if */
59
		($1)[1] = (Inst)$5;	/* thenpart */
60
		($1)[3] = (Inst)$6; }	/* end, if cond fails */
61
	| if '(' cond ')' stmt end ELSE stmt end {	/* if with else */
62
		($1)[1] = (Inst)$5;	/* thenpart */
63
		($1)[2] = (Inst)$8;	/* elsepart */
64
		($1)[3] = (Inst)$9; }	/* end, if cond fails */
65
	| '{' stmtlist '}'	{ $$ = $2; }
66
	;
67
cond:	   expr 	{ code(STOP); }
68
	;
69
while:	  WHILE	{ $$ = code3(whilecode,STOP,STOP); }
70
	;
71
for:	  FOR	{ $$ = code(forcode); code3(STOP,STOP,STOP); code(STOP); }
72
	;
73
if:	  IF	{ $$ = code(ifcode); code3(STOP,STOP,STOP); }
74
	;
75
begin:	  /* nothing */		{ $$ = progp; }
76
	;
77
end:	  /* nothing */		{ code(STOP); $$ = progp; }
78
	;
79
stmtlist: /* nothing */		{ $$ = progp; }
80
	| stmtlist '\n'
81
	| stmtlist stmt
82
	;
83
expr:	  NUMBER { $$ = code2(constpush, (Inst)$1); }
84
	| VAR	 { $$ = code3(varpush, (Inst)$1, eval); }
85
	| asgn
86
	| FUNCTION begin '(' arglist ')'
87
		{ $$ = $2; code3(call,(Inst)$1,(Inst)$4); }
88
	| READ '(' VAR ')' { $$ = code2(varread, (Inst)$3); }
89
	| BLTIN '(' expr ')' { $$=$3; code2(bltin, (Inst)$1->u.ptr); }
90
	| '(' expr ')'	{ $$ = $2; }
91
	| expr '+' expr	{ code(add); }
92
	| expr '-' expr	{ code(sub); }
93
	| expr '*' expr	{ code(mul); }
94
	| expr '/' expr	{ code(div); }
95
	| expr '%' expr	{ code(mod); }
96
	| expr '^' expr	{ code (power); }
97
	| '-' expr   %prec UNARYMINUS   { $$=$2; code(negate); }
98
	| expr GT expr	{ code(gt); }
99
	| expr GE expr	{ code(ge); }
100
	| expr LT expr	{ code(lt); }
101
	| expr LE expr	{ code(le); }
102
	| expr EQ expr	{ code(eq); }
103
	| expr NE expr	{ code(ne); }
104
	| expr AND expr	{ code(and); }
105
	| expr OR expr	{ code(or); }
106
	| NOT expr	{ $$ = $2; code(not); }
107
	| INC VAR	{ $$ = code2(preinc,(Inst)$2); }
108
	| DEC VAR	{ $$ = code2(predec,(Inst)$2); }
109
	| VAR INC	{ $$ = code2(postinc,(Inst)$1); }
110
	| VAR DEC	{ $$ = code2(postdec,(Inst)$1); }
111
	;
112
prlist:	  expr			{ code(prexpr); }
113
	| STRING		{ $$ = code2(prstr, (Inst)$1); }
114
	| prlist ',' expr	{ code(prexpr); }
115
	| prlist ',' STRING	{ code2(prstr, (Inst)$3); }
116
	;
117
defn:	  FUNC procname { $2->type=FUNCTION; indef=1; }
118
	    '(' formals ')' stmt { code(procret); define($2, $5); indef=0; }
119
	| PROC procname { $2->type=PROCEDURE; indef=1; }
120
	    '(' formals ')' stmt { code(procret); define($2, $5); indef=0; }
121
	;
122
formals:	{ $$ = 0; }
123
	| VAR			{ $$ = formallist($1, 0); }
124
	| VAR ',' formals	{ $$ = formallist($1, $3); }
125
	;
126
procname: VAR
127
	| FUNCTION
128
	| PROCEDURE
129
	;
130
arglist:  /* nothing */ 	{ $$ = 0; }
131
	| expr			{ $$ = 1; }
132
	| arglist ',' expr	{ $$ = $1 + 1; }
133
	;
134
%%
135
	/* end of grammar */
136
#include <u.h>
137
#include <libc.h>
138
#include <bio.h>
139
#include <ctype.h>
140
char	*progname;
141
int	lineno = 1;
142
jmp_buf	begin;
143
int	indef;
144
char	*infile;	/* input file name */
145
Biobuf	*bin;		/* input file descriptor */
146
Biobuf	binbuf;
147
char	**gargv;	/* global argument list */
148
int	gargc;
149
 
150
int c = '\n';	/* global for use by warning() */
151
 
152
int	backslash(int), follow(int, int, int);
153
void	defnonly(char*), run(void);
154
void	warning(char*, char*);
155
 
156
yylex(void)		/* hoc6 */
157
{
158
	while ((c=Bgetc(bin)) == ' ' || c == '\t')
159
		;
160
	if (c < 0)
161
		return 0;
162
	if (c == '\\') {
163
		c = Bgetc(bin);
164
		if (c == '\n') {
165
			lineno++;
166
			return yylex();
167
		}
168
	}
169
	if (c == '#') {		/* comment */
170
		while ((c=Bgetc(bin)) != '\n' && c >= 0)
171
			;
172
		if (c == '\n')
173
			lineno++;
174
		return c;
175
	}
176
	if (c == '.' || isdigit(c)) {	/* number */
177
		double d;
178
		Bungetc(bin);
179
		Bgetd(bin, &d);
180
		yylval.sym = install("", NUMBER, d);
181
		return NUMBER;
182
	}
183
	if (isalpha(c) || c == '_' || c >= 0x80) {
184
		Symbol *s;
185
		char sbuf[100], *p = sbuf;
186
		do {
187
			if (p >= sbuf + sizeof(sbuf) - 1) {
188
				*p = '\0';
189
				execerror("name too long", sbuf);
190
			}
191
			*p++ = c;
192
		} while ((c=Bgetc(bin)) >= 0 && (isalnum(c) || c == '_' || c >= 0x80));
193
		Bungetc(bin);
194
		*p = '\0';
195
		if ((s=lookup(sbuf)) == 0)
196
			s = install(sbuf, UNDEF, 0.0);
197
		yylval.sym = s;
198
		return s->type == UNDEF ? VAR : s->type;
199
	}
200
	if (c == '"') {	/* quoted string */
201
		char sbuf[100], *p;
202
		for (p = sbuf; (c=Bgetc(bin)) != '"'; p++) {
203
			if (c == '\n' || c == Beof)
204
				execerror("missing quote", "");
205
			if (p >= sbuf + sizeof(sbuf) - 1) {
206
				*p = '\0';
207
				execerror("string too long", sbuf);
208
			}
209
			*p = backslash(c);
210
		}
211
		*p = 0;
212
		yylval.sym = (Symbol *)emalloc(strlen(sbuf)+1);
213
		strcpy((char*)yylval.sym, sbuf);
214
		return STRING;
215
	}
216
	switch (c) {
217
	case '+':	return follow('+', INC, follow('=', ADDEQ, '+'));
218
	case '-':	return follow('-', DEC, follow('=', SUBEQ, '-'));
219
	case '*':	return follow('=', MULEQ, '*');
220
	case '/':	return follow('=', DIVEQ, '/');
221
	case '%':	return follow('=', MODEQ, '%');
222
	case '>':	return follow('=', GE, GT);
223
	case '<':	return follow('=', LE, LT);
224
	case '=':	return follow('=', EQ, '=');
225
	case '!':	return follow('=', NE, NOT);
226
	case '|':	return follow('|', OR, '|');
227
	case '&':	return follow('&', AND, '&');
228
	case '\n':	lineno++; return '\n';
229
	default:	return c;
230
	}
231
}
232
 
233
backslash(int c)	/* get next char with \'s interpreted */
234
{
235
	static char transtab[] = "b\bf\fn\nr\rt\t";
236
	if (c != '\\')
237
		return c;
238
	c = Bgetc(bin);
239
	if (islower(c) && strchr(transtab, c))
240
		return strchr(transtab, c)[1];
241
	return c;
242
}
243
 
244
follow(int expect, int ifyes, int ifno)	/* look ahead for >=, etc. */
245
{
246
	int c = Bgetc(bin);
247
 
248
	if (c == expect)
249
		return ifyes;
250
	Bungetc(bin);
251
	return ifno;
252
}
253
 
254
void
255
yyerror(char* s)	/* report compile-time error */
256
{
257
/*rob
258
	warning(s, (char *)0);
259
	longjmp(begin, 0);
260
rob*/
261
	execerror(s, (char *)0);
262
}
263
 
264
void
265
execerror(char* s, char* t)	/* recover from run-time error */
266
{
267
	warning(s, t);
268
	Bseek(bin, 0L, 2);		/* flush rest of file */
269
	restoreall();
270
	longjmp(begin, 0);
271
}
272
 
273
void
274
fpecatch(void)	/* catch floating point exceptions */
275
{
276
	execerror("floating point exception", (char *) 0);
277
}
278
 
279
void
280
intcatch(void)	/* catch interrupts */
281
{
282
	execerror("interrupt", 0);
283
}
284
 
285
void
286
run(void)	/* execute until EOF */
287
{
288
	setjmp(begin);
289
	for (initcode(); yyparse(); initcode())
290
		execute(progbase);
291
}
292
 
293
void
294
main(int argc, char* argv[])	/* hoc6 */
295
{
296
	static int first = 1;
297
#ifdef YYDEBUG
298
	extern int yydebug;
299
	yydebug=3;
300
#endif
301
	progname = argv[0];
302
	init();
303
	if (argc == 1) {	/* fake an argument list */
304
		static char *stdinonly[] = { "-" };
305
 
306
		gargv = stdinonly;
307
		gargc = 1;
308
	} else if (first) {	/* for interrupts */
309
		first = 0;
310
		gargv = argv+1;
311
		gargc = argc-1;
312
	}
313
	Binit(&binbuf, 0, OREAD);
314
	bin = &binbuf;
315
	while (moreinput())
316
		run();
317
	exits(0);
318
}
319
 
320
moreinput(void)
321
{
322
	char *expr;
323
	static char buf[64];
324
	int fd;
325
	static Biobuf b;
326
 
327
	if (gargc-- <= 0)
328
		return 0;
329
	if (bin && bin != &binbuf)
330
		Bterm(bin);
331
	infile = *gargv++;
332
	lineno = 1;
333
	if (strcmp(infile, "-") == 0) {
334
		bin = &binbuf;
335
		infile = 0;
336
		return 1;
337
	}
338
	if(strncmp(infile, "-e", 2) == 0) {
339
		if(infile[2]==0){
340
			if(gargc == 0){
341
				fprint(2, "%s: no argument for -e\n", progname);
342
				return 0;
343
			}
344
			gargc--;
345
			expr = *gargv++;
346
		}else
347
			expr = infile+2;
348
		sprint(buf, "/tmp/hocXXXXXXX");
349
		infile = mktemp(buf);
350
		fd = create(infile, ORDWR|ORCLOSE, 0600);
351
		if(fd < 0){
352
			fprint(2, "%s: can't create temp. file: %r\n", progname);
353
			return 0;
354
		}
355
		fprint(fd, "%s\n", expr);
356
		/* leave fd around; file will be removed on exit */
357
		/* the following looks weird but is required for unix version */
358
		bin = &b;
359
		seek(fd, 0, 0);
360
		Binit(bin, fd, OREAD);
361
	} else {
362
		bin=Bopen(infile, OREAD);
363
		if (bin == 0) {
364
			fprint(2, "%s: can't open %s\n", progname, infile);
365
			return moreinput();
366
		}
367
	}
368
	return 1;
369
}
370
 
371
void
372
warning(char* s, char* t)	/* print warning message */
373
{
374
	fprint(2, "%s: %s", progname, s);
375
	if (t)
376
		fprint(2, " %s", t);
377
	if (infile)
378
		fprint(2, " in %s", infile);
379
	fprint(2, " near line %d\n", lineno);
380
	while (c != '\n' && c != Beof)
381
		if((c = Bgetc(bin)) == '\n')	/* flush rest of input line */
382
			lineno++;
383
}
384
 
385
void
386
defnonly(char *s)	/* warn if illegal definition */
387
{
388
	if (!indef)
389
		execerror(s, "used outside definition");
390
}