mirror of https://github.com/stella-emu/stella.git
You know, when adding a directory to a proejct, it's often beneficial
to "cvs add" it... git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@586 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
073ae410ad
commit
e91ac28927
|
@ -0,0 +1,17 @@
|
|||
|
||||
### Note: this Makefile not used in building the main Stella binary!
|
||||
|
||||
# can use "yacc" instead of "bison -y"
|
||||
|
||||
all: stella.y
|
||||
bison -y -d stella.y
|
||||
|
||||
calctest: stella.y calctest.c YaccParser.cxx YaccParser.hxx
|
||||
bison -y -d stella.y
|
||||
g++ -DPRINT -O2 -c YaccParser.cxx
|
||||
g++ -O2 -c calctest.c
|
||||
g++ -O2 -Wall -o calctest calctest.o YaccParser.o
|
||||
strip calctest
|
||||
|
||||
#clean:
|
||||
# rm -f y.tab.* lex.yy.* *.o calctest
|
|
@ -0,0 +1,27 @@
|
|||
Makefile.yacc - Not part of the regular stella build!
|
||||
YaccParser.cxx - C++ wrapper for generated parser, includes hand-coded lexer
|
||||
YaccParser.hxx - Include in user code, declares public "methods" (actually functions)
|
||||
calctest.c - Not part of stella! Used for testing the lexel/parser.
|
||||
module.mk - Used for regular Stella build
|
||||
stella.y - Yacc/Bison source for parser
|
||||
y.tab.c, y.tab.h - Generated parser. NOT BUILT AUTOMATICALLY!
|
||||
|
||||
I've only tested stella.y with GNU bison 1.35 and (once) with Berkeley
|
||||
Yacc 1.9. Hopefully your favorite version will work, too :)
|
||||
|
||||
Even though they're generated, y.tab.c and .h are in CVS. This is so that
|
||||
people who don't have a local copy of bison or yacc can still compile
|
||||
Stella.
|
||||
|
||||
If you modify stella.y, you MUST run "make -f Makefile.yacc" in this directory.
|
||||
This will regenerate y.tab.c and y.tab.h. Do this before "cvs commit".
|
||||
|
||||
If you're hacking the parser, you can test it without the rest of Stella
|
||||
by running "make -f Makefile.yacc calctest" in this directory, then running
|
||||
calctest with an expression as its argument:
|
||||
|
||||
./calctest '2+2'
|
||||
= 4
|
||||
|
||||
If you're trying to benchmark the lexer/parser, try adding -DBM to the
|
||||
g++ command that builds calctest.
|
|
@ -0,0 +1,162 @@
|
|||
|
||||
|
||||
//#include "YaccParser.hxx"
|
||||
|
||||
namespace YaccParser {
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int result;
|
||||
//#include "y.tab.h"
|
||||
#include "y.tab.c"
|
||||
|
||||
|
||||
int getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const char *input, *c;
|
||||
|
||||
enum {
|
||||
ST_DEFAULT,
|
||||
ST_NUMBER,
|
||||
ST_OPERATOR,
|
||||
ST_SPACE
|
||||
};
|
||||
|
||||
int state = ST_DEFAULT;
|
||||
|
||||
//extern int yylval; // bison provides this
|
||||
|
||||
void setInput(const char *in) {
|
||||
input = c = in;
|
||||
state = ST_DEFAULT;
|
||||
}
|
||||
|
||||
int parse(const char *in) {
|
||||
setInput(in);
|
||||
return yyparse();
|
||||
}
|
||||
|
||||
/* hand-rolled lexer. Hopefully faster than flex... */
|
||||
|
||||
#define is_operator(x) ( (x=='+' || x=='-' || x=='*' || \
|
||||
x=='/' || x=='<' || x=='>' || \
|
||||
x=='|' || x=='&' || x=='^' || \
|
||||
x=='!' || x=='~' || x=='(' || \
|
||||
x==')' || x=='=' ) )
|
||||
|
||||
int yylex() {
|
||||
char o, p;
|
||||
yylval = 0;
|
||||
while(*c != '\0') {
|
||||
//fprintf(stderr, "looking at %c, state %d\n", *c, state);
|
||||
switch(state) {
|
||||
case ST_SPACE:
|
||||
yylval = 0;
|
||||
if(isspace(*c)) {
|
||||
c++;
|
||||
} else if(isdigit(*c)) {
|
||||
state = ST_NUMBER;
|
||||
} else if(is_operator(*c)) {
|
||||
state = ST_OPERATOR;
|
||||
} else {
|
||||
state = ST_DEFAULT;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ST_NUMBER:
|
||||
while(isdigit(*c)) {
|
||||
yylval *= 10;
|
||||
yylval += (*c++ - '0');
|
||||
//fprintf(stderr, "yylval==%d, *c==%c\n", yylval, *c);
|
||||
}
|
||||
state = ST_DEFAULT;
|
||||
return NUMBER;
|
||||
/*
|
||||
if(isdigit(*c)) {
|
||||
yylval *= 10;
|
||||
yylval += (*c - '0');
|
||||
c++;
|
||||
//fprintf(stderr, "*c==0? %d\n", *c==0);
|
||||
if(*c == '\0') return NUMBER;
|
||||
break;
|
||||
} else {
|
||||
state = ST_DEFAULT;
|
||||
return NUMBER;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
case ST_OPERATOR:
|
||||
o = *c++;
|
||||
if(!*c) return o;
|
||||
if(isspace(*c)) {
|
||||
state = ST_SPACE;
|
||||
return o;
|
||||
} else if(isdigit(*c)) {
|
||||
state = ST_NUMBER;
|
||||
return o;
|
||||
} else {
|
||||
state = ST_DEFAULT;
|
||||
p = *c++;
|
||||
//fprintf(stderr, "o==%c, p==%c\n", o, p);
|
||||
if(o == '>' && p == '=')
|
||||
return GTE;
|
||||
else if(o == '<' && p == '=')
|
||||
return LTE;
|
||||
else if(o == '!' && p == '=')
|
||||
return NE;
|
||||
else if(o == '=' && p == '=')
|
||||
return EQ;
|
||||
else if(o == '|' && p == '|')
|
||||
return LOG_OR;
|
||||
else if(o == '&' && p == '&')
|
||||
return LOG_AND;
|
||||
else if(o == '<' && p == '<')
|
||||
return SHL;
|
||||
else if(o == '>' && p == '>')
|
||||
return SHR;
|
||||
else {
|
||||
c--;
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ST_DEFAULT:
|
||||
default:
|
||||
yylval = 0;
|
||||
if(isspace(*c)) {
|
||||
state = ST_SPACE;
|
||||
} else if(isdigit(*c)) {
|
||||
state = ST_NUMBER;
|
||||
} else if(is_operator(*c)) {
|
||||
state = ST_OPERATOR;
|
||||
} else {
|
||||
yylval = *c++;
|
||||
return yylval;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//fprintf(stderr, "end of input\n");
|
||||
return 0; // hit NUL, end of input.
|
||||
}
|
||||
|
||||
#if 0
|
||||
int main(int argc, char **argv) {
|
||||
int l;
|
||||
|
||||
set_input(argv[1]);
|
||||
while( (l = yylex()) != 0 )
|
||||
printf("ret %d, %d\n", l, yylval);
|
||||
|
||||
printf("%d\n", yylval);
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
#ifndef PARSER_HXX
|
||||
#define PARSER_HXX
|
||||
|
||||
namespace YaccParser {
|
||||
int parse(const char *);
|
||||
int getResult();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "YaccParser.hxx"
|
||||
|
||||
//extern int YaccParser::yyparse();
|
||||
//extern void YaccParser::set_input(const char *);
|
||||
//extern int yyrestart(FILE *);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
#ifndef BM
|
||||
YaccParser::parse(argv[1]);
|
||||
printf("= %d\n", YaccParser::getResult());
|
||||
#else
|
||||
char buf[10];
|
||||
|
||||
for(int i=0; i<1000000; i++) {
|
||||
sprintf(buf, "(1<2)&(3+4)");
|
||||
YaccParser::parse(buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
MODULE := src/yacc
|
||||
|
||||
MODULE_OBJS := \
|
||||
src/yacc/YaccParser.o
|
||||
|
||||
MODULE_DIRS += \
|
||||
src/yacc
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/common.rules
|
|
@ -0,0 +1,65 @@
|
|||
%{
|
||||
#include <stdio.h>
|
||||
|
||||
#define YYERROR_VERBOSE 1
|
||||
|
||||
int yylex();
|
||||
char *yytext;
|
||||
|
||||
void yyerror(char *e) {
|
||||
//fprintf(stderr, "%s at token \"%s\"\n", e, yytext);
|
||||
fprintf(stderr, "%s\n", e);
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%token NUMBER
|
||||
%left '-' '+'
|
||||
%left '*' '/' '%'
|
||||
%left LOG_OR
|
||||
%left LOG_AND
|
||||
%left '|' '^'
|
||||
%left '&'
|
||||
%left SHR SHL
|
||||
%nonassoc UMINUS '<' '>' GTE LTE NE EQ
|
||||
|
||||
%%
|
||||
statement: expression { result = $1; }
|
||||
;
|
||||
|
||||
expression: expression '+' expression { $$ = $1 + $3; }
|
||||
| expression '-' expression { $$ = $1 - $3; }
|
||||
| expression '*' expression { $$ = $1 * $3; }
|
||||
| expression '/' expression
|
||||
{ if($3 == 0)
|
||||
yyerror("divide by zero");
|
||||
else
|
||||
$$ = $1 / $3;
|
||||
}
|
||||
| expression '%' expression
|
||||
{ if($3 == 0)
|
||||
yyerror("divide by zero");
|
||||
else
|
||||
$$ = $1 % $3;
|
||||
}
|
||||
| expression '&' expression { $$ = $1 & $3; }
|
||||
| expression '|' expression { $$ = $1 | $3; }
|
||||
| expression '^' expression { $$ = $1 ^ $3; }
|
||||
| expression '>' expression { $$ = $1 > $3; }
|
||||
| expression '<' expression { $$ = $1 < $3; }
|
||||
| expression GTE expression { $$ = $1 >= $3; }
|
||||
| expression LTE expression { $$ = $1 <= $3; }
|
||||
| expression NE expression { $$ = $1 != $3; }
|
||||
| expression EQ expression { $$ = $1 == $3; }
|
||||
| expression SHR expression { $$ = $1 >> $3; }
|
||||
| expression SHL expression { $$ = $1 << $3; }
|
||||
| expression LOG_OR expression { $$ = $1 || $3; }
|
||||
| expression LOG_AND expression { $$ = $1 && $3; }
|
||||
| '-' expression %prec UMINUS { $$ = -$2; }
|
||||
| '~' expression %prec UMINUS { $$ = (~$2) & 0xffff; }
|
||||
| '<' expression %prec UMINUS { $$ = $2 & 0xff; }
|
||||
| '>' expression %prec UMINUS { $$ = ($2 >> 8) & 0xff; }
|
||||
| '(' expression ')' { $$ = $2; }
|
||||
| NUMBER
|
||||
;
|
||||
%%
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,22 @@
|
|||
#ifndef BISON_Y_TAB_H
|
||||
# define BISON_Y_TAB_H
|
||||
|
||||
# ifndef YYSTYPE
|
||||
# define YYSTYPE int
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# endif
|
||||
# define NUMBER 257
|
||||
# define LOG_OR 258
|
||||
# define LOG_AND 259
|
||||
# define SHR 260
|
||||
# define SHL 261
|
||||
# define UMINUS 262
|
||||
# define GTE 263
|
||||
# define LTE 264
|
||||
# define NE 265
|
||||
# define EQ 266
|
||||
|
||||
|
||||
extern YYSTYPE yylval;
|
||||
|
||||
#endif /* not BISON_Y_TAB_H */
|
Loading…
Reference in New Issue