Added debug information to bison generated parser.

parent 7dd1e1a8
......@@ -7,3 +7,4 @@
*.pdf
*.toc
*.synctex.gz
/build
BUILD=build/
# Fix pdflatex search path
......@@ -9,21 +8,29 @@ TEXGREP := grep -i ".*:[0-9]*:.*\|warning"
TGT_DIR :=
TGT_DOC :=
# Default target is 'all'. The 'build' target is defined here so that all
# sub rules.mk can add prerequisites to the 'build' target.
all:
build:
d := docs/
include base.mk
include $(d)/rules.mk
.PHONY: docs
d := external/
include base.mk
include $(d)/rules.mk
d := tests/
include base.mk
include $(d)/rules.mk
.PHONY: doc
all: docs
all: doc build
clean:
rm -rf $(CLEAN)
docs: $(TGT_DOC)
$(TGT_DIR):
mkdir -p $(TGT_DIR)
$(b)%.pdf: $(d)%.tex $(TGT_DIR)
pdflatex $(TEXFLAGS) -output-directory `dirname $@` $< | ${TEXGREP} || true
.PHONY: docs
TGT_DOC += $(b)proposal.pdf
doc: $(TGT_DOC)
$(b)%.pdf: $(d)%.tex $(TGT_DIR)
pdflatex $(TEXFLAGS) -output-directory `dirname $@` $< | ${TEXGREP} || true
pybison @ 9c01c2ce
Subproject commit a8765c6130a70855967527f61e527b13ce5143f5
Subproject commit 9c01c2cea1d39f5334c9e987eb40dfb25788862e
TGT_DIR += $(b)pybison
PYBISON_INC := -Iexternal/pybison/src/c -I/usr/include/python2.7
build: $(b)pybison/bison_.so $(b)pybison/bison.py
$(b)pybison/bison_.so: $(b)pybison/bison_.o $(b)pybison/bisondynlib-linux.o
$(CC) -g -O0 -pipe -Wall -Wextra -shared -pthread -o $@ $^
$(b)pybison/bison.py: $(d)pybison/src/python/bison.py | $(b)pybison
ln -s `realpath $<` $@
$(b)pybison/bisondynlib-linux.o $(b)pybison/bison_.o: | $(b)pybison
$(CC) -g -O0 -pipe -Wall -Wextra -o $@ -c $< -pthread -fPIC $(PYBISON_INC)
$(b)pybison/bisondynlib-linux.o: $(d)pybison/src/c/bisondynlib-linux.c
$(b)pybison/bison_.o: $(b)pybison/bison_.c
$(b)pybison/%.c: $(d)pybison/src/pyrex/%.pyx
pyrexc -o $@ $<
#!/usr/bin/env python
"""
A simple pybison parser program implementing a calculator
"""
import os.path
PYBISON_BUILD = os.path.realpath('build/external/pybison')
PYBISON_PYREX = os.path.realpath('external/pybison/src/pyrex')
import sys
sys.path.insert(0, PYBISON_BUILD)
sys.path.insert(1, PYBISON_PYREX)
from bison import BisonParser, BisonNode
class Parser(BisonParser):
"""
Implements the calculator parser. Grammar rules are defined in the method
docstrings. Scanner rules are in the 'lexscript' attribute.
"""
# Output directory of generated pybison files, including a trailing slash.
buildDirectory = PYBISON_BUILD + '/'
# ----------------------------------------------------------------
# lexer tokens - these must match those in your lex script (below)
# ----------------------------------------------------------------
tokens = ['NUMBER',
'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'POW',
'LPAREN', 'RPAREN',
'NEWLINE', 'QUIT']
# ------------------------------
# precedences
# ------------------------------
precedences = (
('left', ('MINUS', 'PLUS')),
('left', ('TIMES', 'DIVIDE')),
('left', ('NEG', )),
('right', ('POW', )),
)
# ------------------------------------------------------------------
# override default read method with a version that prompts for input
# ------------------------------------------------------------------
def read(self, nbytes):
try:
return raw_input("> ") + "\n"
except EOFError:
return ''
# ---------------------------------------------------------------
# These methods are the python handlers for the bison targets.
# (which get called by the bison code each time the corresponding
# parse target is unambiguously reached)
#
# WARNING - don't touch the method docstrings unless you know what
# you are doing - they are in bison rule syntax, and are passed
# verbatim to bison to build the parser engine library.
# ---------------------------------------------------------------
# Declare the start target here (by name)
start = "input"
def on_input(self, target, option, names, values):
"""
input :
| input line
"""
return
def on_line(self, target, option, names, values):
"""
line : NEWLINE
| exp NEWLINE
"""
if option == 1:
print 'option:', option
#print 'on_line:', values[0]
def on_exp(self, target, option, names, values):
"""
exp : NUMBER
| exp PLUS exp
| exp MINUS exp
| exp TIMES exp
| exp DIVIDE exp
| MINUS exp %prec NEG
| exp POW exp
| LPAREN exp RPAREN
"""
print 'on_exp: got %s %s %s %s' % (target, option, names, values)
if option == 0:
return
#return float(values[0])
elif option == 1:
return
#return values[0] + values[2]
elif option == 2:
return values[0] - values[2]
elif option == 3:
return values[0] * values[2]
elif option == 4:
return values[0] / values[2]
elif option == 5:
return - values[1]
elif option == 6:
return values[0] ** values[2]
elif option == 7:
return values[1]
# -----------------------------------------
# raw lex script, verbatim here
# -----------------------------------------
lexscript = r"""
%{
//int yylineno = 0;
#include <stdio.h>
#include <string.h>
#include "Python.h"
#define YYSTYPE void *
#include "tokens.h"
extern void *py_parser;
extern void (*py_input)(PyObject *parser, char *buf, int *result, int max_size);
#define returntoken(tok) yylval = PyString_FromString(strdup(yytext)); return (tok);
#define YY_INPUT(buf,result,max_size) { (*py_input)(py_parser, buf, &result, max_size); }
%}
%%
[0-9]+ { returntoken(NUMBER); }
"(" { returntoken(LPAREN); }
")" { returntoken(RPAREN); }
"+" { returntoken(PLUS); }
"-" { returntoken(MINUS); }
"*" { returntoken(TIMES); }
"**" { returntoken(POW); }
"/" { returntoken(DIVIDE); }
"quit" { printf("lex: got QUIT\n"); yyterminate(); returntoken(QUIT); }
[ \t\v\f] {}
[\n] {yylineno++; returntoken(NEWLINE); }
. { printf("unknown char %c ignored, yytext=0x%lx\n", yytext[0], yytext); /* ignore bad chars */}
%%
yywrap() { return(1); }
"""
if __name__ == '__main__':
p = Parser(verbose=0, keepfiles=1)
p.run(debug=1)
import logging
import logging.config
import sys
import config
import default_config as default
try:
logging.basicConfig(level=logging.DEBUG,
format=getattr(config, 'LOG_FORMAT', default.LOG_FORMAT),
filename=getattr(config, 'LOG_FILE', default.LOG_FILE),
filemode='a')
except IOError as e: # pragma: no cover
print >>sys.stderr, 'warning: IOError raised: "%s"' % str(e)
def logger(name):
return logging.getLogger(name)
from testrunner import main
import sys
main(sys.argv[1:])
TESTS=$(wildcard tests/test_*.py)
COVERAGE_OUTPUT_DIR := coverage
OMIT := --omit /usr/share/pyshared/*,/usr/lib64/portage/*
ifeq ($(findstring python-coverage,$(wildcard /usr/bin/*)), python-coverage)
COVERAGE=/usr/bin/python-coverage
else
COVERAGE=/usr/bin/coverage
endif
.PHONY: test coverage $(TESTS)
test: $(TESTS) build
coverage: ${COVERAGE}
mkdir ${COVERAGE_OUTPUT_DIR} 2>/dev/null || true
${COVERAGE} erase
for t in ${TESTS}; do \
echo $$t; \
${COVERAGE} ${OMIT} -x test.py $$t; \
${COVERAGE} ${OMIT} -c; \
done
${COVERAGE} html ${OMIT} --dir ${COVERAGE_OUTPUT_DIR}
${COVERAGE}:
@echo "Install package 'python-coverage' to generate a coverage report."
@echo "On Debian/Ubuntu use: sudo apt-get install python-coverage"; false
$(TESTS): ; @python -m testrunner $@
import unittest
class TestCalc(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_true(self):
assert True
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment