skel/skel_bison.h.orig
tests/*.c
tests/*.o
-tests/*.py
tests/*.xml
+tests/lex_yy.py
+tests/y_tab.py
tests/cal
tests/cal2
+tests_ast/*.xml
+tests_ast/lex_yy.py
+tests_ast/y_tab.py
0x5c: '\\\\'
}
-def generate_bison(_ast, home_dir, skel_file, out_file, defines_file = None):
+def generate_bison(
+ _ast,
+ _element,
+ home_dir,
+ skel_file,
+ out_file,
+ defines_file = None
+):
_lr1dfa = _ast.to_lr1().to_lalr1()
# generate translate table for terminal symbols
lines[j] = '{0:s}{1:s}\n'.format(indent, lines[j][len(prefix):])
return ''.join(lines)
-def generate_py(_ast, home_dir, skel_file, out_file, defines_file = None):
+def generate_py(
+ _ast,
+ _element,
+ home_dir,
+ skel_file,
+ out_file,
+ defines_file = None
+):
_lr1dfa = _ast.to_lr1().to_lalr1()
assert _lr1dfa.eof_terminal == 0
actions = [i for _, i in _lr1dfa.productions]
]
if skel_file is None:
- skel_file = os.path.join(home_dir, 'skel/skel_py.py')
+ skel_file = os.path.join(
+ home_dir,
+ 'skel/skel_py_element.py' if _element else 'skel/skel_py.py'
+ )
if out_file is None:
out_file = 'y_tab.py'
with open(skel_file, 'r') as fin:
try:
opts, args = getopt.getopt(
sys.argv[1:],
- 'do:pS:',
- ['defines=', 'outfile=', 'python', 'skel=']
+ 'edo:pS:',
+ ['element', 'defines=', 'outfile=', 'python', 'skel=']
)
except getopt.GetoptError as err:
sys.stderr.write('{0:s}\n'.format(str(err)))
sys.exit(1)
defines_file = None
+_element = False
out_file = None
python = False
skel_file = None
defines_file = 'y.tab.h'
elif opt == '--defines':
defines_file = arg
+ elif opt == '-e' or opt == '--element':
+ _element = True
elif opt == '-o' or opt == '--outfile':
out_file = arg
elif opt == '-p' or opt == '--python':
#_ast = element.deserialize('b.xml', ast.factory, 'utf-8')
(generate_py.generate_py if python else generate_bison.generate_bison)(
_ast,
+ _element,
home_dir,
skel_file,
out_file,
# GENERATE TOKENS
-yystack = []
+yystack = None
yytoken = None
yyval = None
--- /dev/null
+import bisect
+import element
+
+# GENERATE SECTION1
+
+# GENERATE TOKENS
+
+yystack = None
+yytoken = None
+
+yyval = None
+yyloc = None
+
+yylval = None
+yylloc = None
+
+yy_element_stack = None
+yy_element_space = None
+yy_element_token = None
+
+# GENERATE SECTION2
+
+def yyparse():
+ global yystack, yytoken, yyval, yyloc, yylval, yylloc
+ global yy_element_stack, yy_element_space, yy_element_token
+
+ # GENERATE INITIALACTION
+
+ state = 0
+ yystack = []
+ yylval = None
+ yytoken = -1
+ yy_element_stack = []
+ while True:
+ #print('state', state, 'yystack', yystack)
+ reduce = yy_lr1dfa_states[state][4]
+ if reduce == -1:
+ if yytoken == -1:
+ yylval = None
+ yylloc = None
+ yytoken = yylex()
+ #print('yytoken', yytoken, 'yylval', yylval, 'yylloc', yylloc)
+ action = yy_lr1dfa_states[state][1][
+ bisect.bisect_right(yy_lr1dfa_states[state][0], yytoken)
+ ]
+ if action == -1:
+ raise Exception('syntax error')
+ if (action & 1) == 0:
+ yystack.append((state, yylval, yylloc))
+
+ # push space then AST element contiguously onto yy_element_stack
+ # even numbered elements are spaces, odd numbered elements are AST
+ yy_element_stack.append(yy_element_space)
+ yy_element_stack.append(yy_element_token)
+
+ state = action >> 1
+ #print('shift', state)
+ yytoken = -1
+ continue
+ reduce = action >> 1
+ #print('reduce', reduce)
+ len_symbols, ref_data = yy_lr1dfa_productions[reduce]
+ base = len(yystack) - len_symbols
+ yystack.append((state, None, None))
+ state, yyval, yyloc = yystack[base]
+ ref_data()
+ del yystack[base:]
+ if reduce == 0:
+ assert base == 0
+ break
+ yystack.append((state, yyval, yyloc))
+
+ # concatenate yy_element_stack[base * 2:] to space then AST element
+ j = base * 2 + 1
+ for i in range(j + 1, len(yy_element_stack)):
+ k = len(yy_element_stack[j])
+ element.set_text(
+ yy_element_stack[j],
+ k,
+ element.get_text(yy_element_stack[j], k) +
+ element.get_text(yy_element_stack[i], 0)
+ )
+ yy_element_stack[j][k:] = yy_element_stack[i][:]
+ del yy_element_stack[j + 1:]
+
+ state = yy_lr1dfa_states[state][3][
+ bisect.bisect_right(yy_lr1dfa_states[state][2], reduce)
+ ]
+ assert state != -1
+
+# GENERATE SECTION3
--- /dev/null
+all: lex_yy.py y_tab.py
+
+lex_yy.py: cal_py.l
+ ../../bootstrap_flex.git/src/flex -o /dev/null $< 2>$<.xml
+ ../../pilex.git/pilex.py --element --python $<.xml
+
+y_tab.py: cal_py.y
+ ../../bootstrap_bison.git/src/bison -o /dev/null $< 2>$<.xml
+ ../piyacc.py --element --python $<.xml
+
+clean:
+ rm -f lex_yy.py y_tab.py *.xml
--- /dev/null
+#!/usr/bin/env python3
+
+import element
+import sys
+import y_tab
+
+sys.stdout.write('Enter the expression: ')
+sys.stdout.flush()
+y_tab.yyparse()
+sys.stdout.write(
+ 'space \'{0:s}\'\nAST \'{1:s}\'\n'.format(
+ element.get_text(y_tab.yy_element_stack[0], 0),
+ element.get_text(y_tab.yy_element_stack[1], 0)
+ )
+)
--- /dev/null
+%{
+import y_tab
+%}
+
+DIGIT [0-9]+\.?|[0-9]*\.[0-9]+
+
+%%
+
+[ ]
+{DIGIT} {
+ y_tab.yylval = float(yytext)
+ return y_tab.NUM
+}
+\n|. {
+ return ord(yytext[0])
+}
--- /dev/null
+%{
+from lex_yy import yylex
+import sys
+%}
+%token NUM
+
+%left '+' '-'
+%left '*' '/'
+%right UMINUS
+
+%%
+
+S : S E '\n' {
+ sys.stdout.write('Answer: {0:g}\nEnter:\n'.format($2))
+}
+ | S '\n'
+ |
+ | error '\n' {
+ yyerror('Error: Enter once more...\n')
+ yyerrok()
+}
+ ;
+E : E '+' E { $$ = $1 + $3 }
+ | E '-' E { $$ = $1 - $3 }
+ | E '*' E { $$ = $1 * $3 }
+ | E '/' E { $$ = $1 / $3 }
+ | '(' E ')' { $$ = $2 }
+ /*| '-' E %prec UMINUS { $$ = -$2 }*/
+ | '-' { print('unary minus', $1) } E %prec UMINUS { $$ = -$3 }
+ | NUM
+ ;
+%%
+
+def yyerror(s):
+ sys.stdout.write('{0:s}\n'.format(s))
+ sys.exit(1)
--- /dev/null
+import xml.etree.ElementTree
+
+class Element(xml.etree.ElementTree._Element_Py):
+ def __init__(self, tag = 'Element', attrib = {}, text = '', children = []):
+ xml.etree.ElementTree._Element_Py.__init__(self, tag, attrib)
+ self.ref = -1
+ self.seen = False
+ set_text(self, 0, text)
+ self[:] = children
+ def serialize(self, ref_list):
+ for i in self:
+ # parented, enforce that child can only be parented at most once
+ # (although there can be unlimited numbers of numeric refs to it)
+ assert not i.seen
+ i.seen = True
+ if i.ref == -1:
+ i.serialize(ref_list)
+ def deserialize(self, ref_list):
+ for i in self:
+ i.deserialize(ref_list)
+ def copy(self, factory = None):
+ result = (Element if factory is None else factory)(self.tag, self.attrib)
+ result.text = self.text
+ result.tail = self.tail
+ result[:] = [i.copy() for i in self]
+ return result
+ def repr_serialize(self, params):
+ if len(self):
+ params.append(
+ 'children = [{0:s}]'.format(
+ ', '.join([repr(i) for i in self])
+ )
+ )
+ def __repr__(self):
+ params = []
+ self.repr_serialize(params)
+ return 'element.Element({0:s})'.format(', '.join(params))
+
+bool_to_str = ['false', 'true']
+def serialize_bool(value):
+ return bool_to_str[int(value)]
+
+str_to_bool = {'false': False, 'true': True}
+def deserialize_bool(text):
+ return str_to_bool[text]
+
+def serialize_int(value):
+ return str(value)
+
+def deserialize_int(text):
+ return int(text)
+
+def serialize_ref(value, ref_list):
+ if value is None:
+ ref = -1
+ else:
+ ref = value.ref
+ if ref == -1:
+ ref = len(ref_list)
+ ref_list.append(value)
+ value.ref = ref
+ value.set('ref', str(ref))
+ # this doesn't set the seen flag, so it will be parented by the
+ # root, unless it is already parented or gets parented later on
+ if not value.seen:
+ value.serialize(ref_list)
+ return str(ref)
+
+def deserialize_ref(text, ref_list):
+ ref = int(text)
+ return None if ref < 0 else ref_list[ref]
+
+def serialize_str(value):
+ return value
+
+def deserialize_str(text):
+ return text
+
+def serialize(value, fout, encoding = 'unicode'):
+ ref_list = []
+ serialize_ref(value, ref_list)
+ parents = [i for i in ref_list if not i.seen]
+ root = Element('root', children = parents)
+ for i in range(len(root)):
+ set_text(root, i, '\n ')
+ set_text(root, len(root), '\n')
+ root.tail = '\n'
+ xml.etree.ElementTree.ElementTree(root).write(fout, encoding)
+ for i in root:
+ i.tail = None
+ for i in ref_list:
+ i.ref = -1
+ del i.attrib['ref']
+ i = 0
+ while i < len(parents):
+ for j in parents[i]:
+ j.seen = False
+ parents.append(j)
+ i += 1
+
+def deserialize(fin, factory = Element, encoding = 'unicode'):
+ root = xml.etree.ElementTree.parse(
+ fin,
+ xml.etree.ElementTree.XMLParser(
+ target = xml.etree.ElementTree.TreeBuilder(factory),
+ encoding = encoding
+ )
+ ).getroot()
+ assert root.tag == 'root'
+ for i in root:
+ i.tail = None
+ i = 0
+ parents = root[:]
+ ref_list = []
+ while i < len(parents):
+ j = parents[i]
+ if 'ref' in j.attrib:
+ ref = int(j.attrib['ref'])
+ del j.attrib['ref']
+ if len(ref_list) < ref + 1:
+ ref_list.extend([None] * (ref + 1 - len(ref_list)))
+ ref_list[ref] = j
+ parents.extend(j[:])
+ i += 1
+ for i in root:
+ i.deserialize(ref_list)
+ return ref_list[0]
+
+# compatibility scheme to access arbitrary xml.etree.ElementTree.Element-like
+# objects (not just Element defined above) using a more consistent interface:
+def get_text(root, i):
+ if i < 0:
+ i += len(root) + 1
+ text = root.text if i == 0 else root[i - 1].tail
+ return '' if text is None else text
+
+def set_text(root, i, text):
+ if i < 0:
+ i += len(root) + 1
+ if len(text) == 0:
+ text = None
+ if i == 0:
+ root.text = text
+ else:
+ root[i - 1].tail = text
+
+def to_end_relative(root, pos, off):
+ assert pos >= 0 and off >= 0
+ off -= len(get_text(root, pos))
+ pos -= len(root) + 1
+ return pos, off
+
+def to_start_relative(root, pos, off):
+ assert pos < 0 and off <= 0
+ pos += len(root) + 1
+ off += len(get_text(root, pos))
+ return pos, off