mirror of
https://github.com/ioquake/ioq3.git
synced 2024-11-10 07:11:46 +00:00
5ede35d8dd
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.
225 lines
4.5 KiB
Text
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);
|
|
}
|