224 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			224 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
%{
 | 
						|
#include <stdio.h>
 | 
						|
#include "lburg.h"
 | 
						|
static char rcsid[] = "$Id$";
 | 
						|
/*lint -e616 -e527 -e652 -esym(552,yynerrs) -esym(563,yynewstate,yyerrlab) */
 | 
						|
int yylineno = 0;
 | 
						|
int linesum = 1;
 | 
						|
extern int yylex(void);
 | 
						|
%}
 | 
						|
%union {
 | 
						|
	int n;
 | 
						|
	char *string;
 | 
						|
	Tree tree;
 | 
						|
}
 | 
						|
%term TERMINAL
 | 
						|
%term START
 | 
						|
%term PPERCENT
 | 
						|
 | 
						|
%token  <string>        ID TEMPLATE CODE
 | 
						|
%token  <n>             INT
 | 
						|
%type	<string>	nonterm cost
 | 
						|
%type   <tree>          tree
 | 
						|
%%
 | 
						|
spec	: decls PPERCENT rules
 | 
						|
	| decls
 | 
						|
	;
 | 
						|
 | 
						|
decls	: /* lambda */
 | 
						|
	| decls decl
 | 
						|
	;
 | 
						|
 | 
						|
decl	: TERMINAL  blist '\n'
 | 
						|
	| START nonterm '\n'		{
 | 
						|
		if (nonterm($2)->number != 1)
 | 
						|
			yyerror("redeclaration of the start symbol\n");
 | 
						|
		}
 | 
						|
	| '\n'
 | 
						|
	| error '\n'			{ yyerrok; }
 | 
						|
	;
 | 
						|
 | 
						|
blist	: /* lambda */
 | 
						|
	| blist ID '=' INT      	{ term($2, $4); }
 | 
						|
	;
 | 
						|
 | 
						|
rules	: /* lambda */
 | 
						|
	| rules nonterm ':' tree TEMPLATE cost '\n'	{ rule($2, $4, $5, $6); }
 | 
						|
	| rules '\n'
 | 
						|
	| rules error '\n'		{ yyerrok; }
 | 
						|
	;
 | 
						|
 | 
						|
nonterm	: ID				{ nonterm($$ = $1); }
 | 
						|
	;
 | 
						|
 | 
						|
tree	: ID                            { $$ = tree($1,  0,  0); }
 | 
						|
	| ID '(' tree ')'               { $$ = tree($1, $3,  0); }
 | 
						|
	| ID '(' tree ',' tree ')'      { $$ = tree($1, $3, $5); }
 | 
						|
	;
 | 
						|
 | 
						|
cost	: CODE				{ if (*$1 == 0) $$ = "0"; }
 | 
						|
	;
 | 
						|
%%
 | 
						|
#include <assert.h>
 | 
						|
#include <stdarg.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <string.h>
 | 
						|
#include <limits.h>
 | 
						|
 | 
						|
int errcnt = 0;
 | 
						|
FILE *infp = NULL;
 | 
						|
FILE *outfp = NULL;
 | 
						|
const char *infname = 0;
 | 
						|
const char *outfname = 0;
 | 
						|
static char buf[BUFSIZ], *bp = buf;
 | 
						|
static int ppercent = 0;
 | 
						|
static int code = 0;
 | 
						|
 | 
						|
static int get(void) {
 | 
						|
	if (*bp == 0) {
 | 
						|
		bp = buf;
 | 
						|
		*bp = 0;
 | 
						|
		if (fgets(buf, sizeof buf, infp) == NULL)
 | 
						|
			return EOF;
 | 
						|
		yylineno++;
 | 
						|
		while (buf[0] == '#') {
 | 
						|
			if (fgets(buf, sizeof buf, infp) == NULL)
 | 
						|
				return EOF;
 | 
						|
			yylineno++;
 | 
						|
		}
 | 
						|
		while (buf[0] == '%' && buf[1] == '{' && buf[2] == '\n') {
 | 
						|
			linesum -= yylineno;
 | 
						|
			if (infname)
 | 
						|
				fprintf(outfp, "#line %d \"%s\"\n", yylineno+1, infname);
 | 
						|
			for (;;) {
 | 
						|
				if (fgets(buf, sizeof buf, infp) == NULL) {
 | 
						|
					yywarn("unterminated %{...%}\n");
 | 
						|
					return EOF;
 | 
						|
				}
 | 
						|
				yylineno++;
 | 
						|
				if (strcmp(buf, "%}\n") == 0)
 | 
						|
					break;
 | 
						|
				fputs(buf, outfp);
 | 
						|
			}
 | 
						|
			if (fgets(buf, sizeof buf, infp) == NULL)
 | 
						|
				return EOF;
 | 
						|
			yylineno++;
 | 
						|
			linesum += yylineno;
 | 
						|
			if (outfname)
 | 
						|
				fprintf(outfp, "#line %d \"%s\"\n", linesum, outfname);
 | 
						|
		}
 | 
						|
		while (buf[0] == '#') {
 | 
						|
			if (fgets(buf, sizeof buf, infp) == NULL)
 | 
						|
				return EOF;
 | 
						|
			yylineno++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return *bp++;
 | 
						|
}
 | 
						|
 | 
						|
void yyerror(char *fmt, ...) {
 | 
						|
	va_list ap;
 | 
						|
 | 
						|
	va_start(ap, fmt);
 | 
						|
	if (yylineno > 0)
 | 
						|
		fprintf(stderr, "line %d: ", yylineno);
 | 
						|
	vfprintf(stderr, fmt, ap);
 | 
						|
	if (fmt[strlen(fmt)-1] != '\n')
 | 
						|
		 fprintf(stderr, "\n");
 | 
						|
	errcnt++;
 | 
						|
	va_end(ap);
 | 
						|
}
 | 
						|
 | 
						|
int yylex(void) {
 | 
						|
	int c;
 | 
						|
 | 
						|
	if (code) {
 | 
						|
		char *p;
 | 
						|
		bp += strspn(bp, " \t\f");
 | 
						|
		p = strchr(bp, '\n');
 | 
						|
		if (p == NULL)
 | 
						|
			p = strchr(bp, '\0');
 | 
						|
		while (p > bp && isspace(p[-1]))
 | 
						|
			p--;
 | 
						|
		yylval.string = alloc(p - bp + 1);
 | 
						|
		strncpy(yylval.string, bp, p - bp);
 | 
						|
		yylval.string[p - bp] = 0;
 | 
						|
		bp = p;
 | 
						|
		code--;
 | 
						|
		return CODE;
 | 
						|
	}
 | 
						|
	while ((c = get()) != EOF) {
 | 
						|
		switch (c) {
 | 
						|
		case ' ': case '\f': case '\t':
 | 
						|
			continue;
 | 
						|
		case '\n':
 | 
						|
		case '(': case ')': case ',':
 | 
						|
		case ':': case '=':
 | 
						|
			return c;
 | 
						|
		}
 | 
						|
		if (c == '%' && *bp == '%') {
 | 
						|
			bp++;
 | 
						|
			return ppercent++ ? 0 : PPERCENT;
 | 
						|
		} else if (c == '%' && strncmp(bp, "term", 4) == 0
 | 
						|
		&& isspace(bp[4])) {
 | 
						|
			bp += 4;
 | 
						|
			return TERMINAL;
 | 
						|
		} else if (c == '%' && strncmp(bp, "start", 5) == 0
 | 
						|
		&& isspace(bp[5])) {
 | 
						|
			bp += 5;
 | 
						|
			return START;
 | 
						|
		} else if (c == '"') {
 | 
						|
			char *p = strchr(bp, '"');
 | 
						|
			if (p == NULL) {
 | 
						|
				yyerror("missing \" in assembler template\n");
 | 
						|
				p = strchr(bp, '\n');
 | 
						|
				if (p == NULL)
 | 
						|
					p = strchr(bp, '\0');
 | 
						|
			}
 | 
						|
			assert(p);
 | 
						|
			yylval.string = alloc(p - bp + 1);
 | 
						|
			strncpy(yylval.string, bp, p - bp);
 | 
						|
			yylval.string[p - bp] = 0;
 | 
						|
			bp = *p == '"' ? p + 1 : p;
 | 
						|
			code++;
 | 
						|
			return TEMPLATE;
 | 
						|
		} else if (isdigit(c)) {
 | 
						|
			int n = 0;
 | 
						|
			do {
 | 
						|
				int d = c - '0';
 | 
						|
				if (n > (INT_MAX - d)/10)
 | 
						|
					yyerror("integer greater than %d\n", INT_MAX);
 | 
						|
				else
 | 
						|
					n = 10*n + d;
 | 
						|
				c = get();
 | 
						|
			} while (c != EOF && isdigit(c));
 | 
						|
			bp--;
 | 
						|
			yylval.n = n;
 | 
						|
			return INT;
 | 
						|
		} else if (isalpha(c)) {
 | 
						|
			char *p = bp - 1;
 | 
						|
			while (isalpha(*bp) || isdigit(*bp) || *bp == '_')
 | 
						|
				bp++;
 | 
						|
			yylval.string = alloc(bp - p + 1);
 | 
						|
			strncpy(yylval.string, p, bp - p);
 | 
						|
			yylval.string[bp - p] = 0;
 | 
						|
			return ID;
 | 
						|
		} else if (isprint(c))
 | 
						|
			yyerror("invalid character `%c'\n", c);
 | 
						|
		else
 | 
						|
			yyerror("invalid character `\\%03o'\n", (unsigned char)c);
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
void yywarn(char *fmt, ...) {
 | 
						|
	va_list ap;
 | 
						|
 | 
						|
	va_start(ap, fmt);
 | 
						|
	if (yylineno > 0)
 | 
						|
		fprintf(stderr, "line %d: ", yylineno);
 | 
						|
	fprintf(stderr, "warning: ");
 | 
						|
	vfprintf(stderr, fmt, ap);
 | 
						|
}
 | 
						|
 |