ioq3/code/tools/lcc/lburg/gram.y
Zack Middleton 5ede35d8dd Fix building QVMs on Linux with Windows line endings
On non-Windows, compiling QVM tools failed if dagcheck.md had CRLF line
endings and compiling QVMs failed if game source had CRLF line endings.

Also made Windows open the files as binary (no automatic CRLF to LF) so
it behaves the same as on non-Windows.
2023-12-26 23:26:47 -05:00

225 lines
4.5 KiB
Text

%{
#include <stdio.h>
#include "lburg.h"
static char rcsid[] = "$Id: gram.y 145 2001-10-17 21:53:10Z timo $";
/*lint -e616 -e527 -e652 -esym(552,yynerrs) -esym(563,yynewstate,yyerrlab) */
static int yylineno = 0;
%}
%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 { yylineno = 0; }
| decls { yylineno = 0; }
;
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;
static char buf[BUFSIZ], *bp = buf;
static int ppercent = 0;
static int code = 0;
static void crlf_to_lf(char *buf, int bufmax) {
int i, count;
count = 0;
for (i = 0; i < bufmax; i++) {
if (buf[i] == '\r' && buf[i+1] == '\n') {
// skip '\r'
continue;
}
buf[count++] = buf[i];
if (buf[i] == '\0') {
break;
}
}
}
static int get(void) {
if (*bp == 0) {
bp = buf;
*bp = 0;
if (fgets(buf, sizeof buf, infp) == NULL)
return EOF;
crlf_to_lf(buf, sizeof buf);
yylineno++;
while (buf[0] == '%' && buf[1] == '{' && buf[2] == '\n') {
for (;;) {
if (fgets(buf, sizeof buf, infp) == NULL) {
yywarn("unterminated %{...%}\n");
return EOF;
}
crlf_to_lf(buf, sizeof buf);
yylineno++;
if (strcmp(buf, "%}\n") == 0)
break;
fputs(buf, outfp);
}
if (fgets(buf, sizeof buf, infp) == NULL)
return EOF;
crlf_to_lf(buf, sizeof buf);
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, '\n');
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);
va_end(ap);
}