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
+def concatenate(children, factory = Element, *args, **kwargs):
+ root = factory(*args, **kwargs)
+ for child in children:
+ i = len(root)
+ set_text(root, i, get_text(root, i) + get_text(child, 0))
+ root[i:] = child[:]
+ return root
import bisect
import element
+import xml.etree.ElementTree
# GENERATE SECTION1
# GENERATE SECTION2
-def yyparse():
+def yyparse(factory, *args, **kwargs):
global yystack, yytoken, yyval, yyloc, yylval, yylloc
global yy_element_stack, yy_element_space, yy_element_token
yy_element_stack = []
while True:
#print('state', state, 'yystack', yystack)
+ assert len(yy_element_stack) == len(yystack) * 2
reduce = yy_lr1dfa_states[state][4]
if reduce == -1:
if yytoken == -1:
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:]
+ i = base * 2
+ #print('i', i, 'len(yy_element_stack)', len(yy_element_stack))
+ if i >= len(yy_element_stack):
+ yy_element_stack.append(element.Element('root'))
+ yy_element_stack.append(element.Element('root'))
+ else:
+ #print('yy_element_stack[i]')
+ #xml.etree.ElementTree.dump(yy_element_stack[i])
+ #print('yy_element_stack[i + 1]')
+ #xml.etree.ElementTree.dump(yy_element_stack[i + 1])
+ for j in range(i + 2, len(yy_element_stack)):
+ #print('j', j)
+ #print('yy_element_stack[j]')
+ #xml.etree.ElementTree.dump(yy_element_stack[j])
+ k = len(yy_element_stack[i + 1])
+ element.set_text(
+ yy_element_stack[i + 1],
+ k,
+ element.get_text(yy_element_stack[i + 1], k) +
+ element.get_text(yy_element_stack[j], 0)
+ )
+ yy_element_stack[i + 1][k:] = yy_element_stack[j][:]
+ del yy_element_stack[i + 2:]
state = yy_lr1dfa_states[state][3][
bisect.bisect_right(yy_lr1dfa_states[state][2], reduce)
]
assert state != -1
+ # return the space then the AST in the user's choice of element type
+ return element.concatenate(yy_element_stack, factory, *args, **kwargs)
+
# GENERATE SECTION3
--- /dev/null
+import element
+
+class AST(element.Element):
+ class Expr(element.Element):
+ # GENERATE ELEMENT() BEGIN
+ def __init__(
+ self,
+ tag = 'AST_Expr',
+ attrib = {},
+ text = '',
+ children = []
+ ):
+ element.Element.__init__(
+ self,
+ tag,
+ attrib,
+ text,
+ children
+ )
+ def copy(self, factory = None):
+ result = element.Element.copy(
+ self,
+ Expr if factory is None else factory
+ )
+ return result
+ def __repr__(self):
+ params = []
+ self.repr_serialize(params)
+ return 'ast.AST.Expr({0:s})'.format(', '.join(params))
+ # GENERATE END
+ def eval(self):
+ raise NotImplementedException()
+
+ class Num(Expr):
+ # GENERATE ELEMENT() BEGIN
+ def __init__(
+ self,
+ tag = 'AST_Num',
+ attrib = {},
+ text = '',
+ children = []
+ ):
+ AST.Expr.__init__(
+ self,
+ tag,
+ attrib,
+ text,
+ children
+ )
+ def copy(self, factory = None):
+ result = AST.Expr.copy(
+ self,
+ Num if factory is None else factory
+ )
+ return result
+ def __repr__(self):
+ params = []
+ self.repr_serialize(params)
+ return 'ast.AST.Num({0:s})'.format(', '.join(params))
+ # GENERATE END
+ def eval(self):
+ return float(element.get_text(self, 0))
+
+ class Add(element.Element):
+ # GENERATE ELEMENT() BEGIN
+ def __init__(
+ self,
+ tag = 'AST_Add',
+ attrib = {},
+ text = '',
+ children = []
+ ):
+ element.Element.__init__(
+ self,
+ tag,
+ attrib,
+ text,
+ children
+ )
+ def copy(self, factory = None):
+ result = element.Element.copy(
+ self,
+ Add if factory is None else factory
+ )
+ return result
+ def __repr__(self):
+ params = []
+ self.repr_serialize(params)
+ return 'ast.AST.Add({0:s})'.format(', '.join(params))
+ # GENERATE END
+ def eval(self):
+ return self[0].eval() + self[1].eval()
+
+ class Sub(element.Element):
+ # GENERATE ELEMENT() BEGIN
+ def __init__(
+ self,
+ tag = 'AST_Sub',
+ attrib = {},
+ text = '',
+ children = []
+ ):
+ element.Element.__init__(
+ self,
+ tag,
+ attrib,
+ text,
+ children
+ )
+ def copy(self, factory = None):
+ result = element.Element.copy(
+ self,
+ Sub if factory is None else factory
+ )
+ return result
+ def __repr__(self):
+ params = []
+ self.repr_serialize(params)
+ return 'ast.AST.Sub({0:s})'.format(', '.join(params))
+ # GENERATE END
+ def eval(self):
+ return self[0].eval() - self[1].eval()
+
+ class Mul(element.Element):
+ # GENERATE ELEMENT() BEGIN
+ def __init__(
+ self,
+ tag = 'AST_Mul',
+ attrib = {},
+ text = '',
+ children = []
+ ):
+ element.Element.__init__(
+ self,
+ tag,
+ attrib,
+ text,
+ children
+ )
+ def copy(self, factory = None):
+ result = element.Element.copy(
+ self,
+ Mul if factory is None else factory
+ )
+ return result
+ def __repr__(self):
+ params = []
+ self.repr_serialize(params)
+ return 'ast.AST.Mul({0:s})'.format(', '.join(params))
+ # GENERATE END
+ def eval(self):
+ return self[0].eval() * self[1].eval()
+
+ class Div(element.Element):
+ # GENERATE ELEMENT() BEGIN
+ def __init__(
+ self,
+ tag = 'AST_Div',
+ attrib = {},
+ text = '',
+ children = []
+ ):
+ element.Element.__init__(
+ self,
+ tag,
+ attrib,
+ text,
+ children
+ )
+ def copy(self, factory = None):
+ result = element.Element.copy(
+ self,
+ Div if factory is None else factory
+ )
+ return result
+ def __repr__(self):
+ params = []
+ self.repr_serialize(params)
+ return 'ast.AST.Div({0:s})'.format(', '.join(params))
+ # GENERATE END
+ def eval(self):
+ return self[0].eval() / self[1].eval()
+
+ class Neg(element.Element):
+ # GENERATE ELEMENT() BEGIN
+ def __init__(
+ self,
+ tag = 'AST_Neg',
+ attrib = {},
+ text = '',
+ children = []
+ ):
+ element.Element.__init__(
+ self,
+ tag,
+ attrib,
+ text,
+ children
+ )
+ def copy(self, factory = None):
+ result = element.Element.copy(
+ self,
+ Neg if factory is None else factory
+ )
+ return result
+ def __repr__(self):
+ params = []
+ self.repr_serialize(params)
+ return 'ast.AST.Neg({0:s})'.format(', '.join(params))
+ # GENERATE END
+ def eval(self):
+ return -self[0].eval()
+
+ # GENERATE ELEMENT() BEGIN
+ def __init__(
+ self,
+ tag = 'AST',
+ attrib = {},
+ text = '',
+ children = []
+ ):
+ element.Element.__init__(
+ self,
+ tag,
+ attrib,
+ text,
+ children
+ )
+ def copy(self, factory = None):
+ result = element.Element.copy(
+ self,
+ AST if factory is None else factory
+ )
+ return result
+ def __repr__(self):
+ params = []
+ self.repr_serialize(params)
+ return 'ast.AST({0:s})'.format(', '.join(params))
+ # GENERATE END
+
+# GENERATE FACTORY(element.Element) BEGIN
+tag_to_class = {
+ 'AST': AST,
+ 'AST_Expr': AST.Expr,
+ 'AST_Num': AST.Num,
+ 'AST_Add': AST.Add,
+ 'AST_Sub': AST.Sub,
+ 'AST_Mul': AST.Mul,
+ 'AST_Div': AST.Div,
+ 'AST_Neg': AST.Neg
+}
+def factory(tag, attrib = {}, *args, **kwargs):
+ return tag_to_class.get(tag, element.Element)(tag, attrib, *args, **kwargs)
+# GENERATE END
--- /dev/null
+#!/bin/sh
+if ../generate_ast.py ast <ast.py >ast.py.new && ! diff -q ast.py ast.py.new
+then
+ mv ast.py.new ast.py
+else
+ rm -f ast.py.new
+fi
#!/usr/bin/env python3
+import ast
import element
import sys
+import xml.etree.ElementTree
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)
- )
-)
+_ast = y_tab.yyparse(ast.AST)
+xml.etree.ElementTree.dump(_ast)
+element.serialize(_ast, 'a.xml', 'utf-8')
+_ast = element.deserialize('a.xml', ast.factory, 'utf-8')
+for i in _ast:
+ sys.stdout.write('{0:g}\n'.format(i.eval()))
%{
+import ast
+import element
import y_tab
%}
[ ]
{DIGIT} {
+ y_tab.yy_element_token = element.Element(
+ 'root',
+ children = [
+ element.concatenate([y_tab.yy_element_token], ast.AST.Num)
+ ]
+ )
y_tab.yylval = float(yytext)
return y_tab.NUM
}
%{
+import ast
from lex_yy import yylex
+import xml.etree.ElementTree
import sys
%}
%token NUM
%%
S : S E '\n' {
- sys.stdout.write('Answer: {0:g}\nEnter:\n'.format($2))
-}
+ sys.stdout.write('Answer: {0:g}\nEnter:\n'.format($2))
+ }
| S '\n'
|
| error '\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 }
+E : E '+' E {
+ yy_element_stack[-5:] = [
+ element.Element(
+ 'root',
+ children = [
+ element.concatenate(yy_element_stack[-5:], ast.AST.Add)
+ ]
+ )
+ ]
+ $$ = $1 + $3
+ }
+ | E '-' E {
+ yy_element_stack[-5:] = [
+ element.Element(
+ 'root',
+ children = [
+ element.concatenate(yy_element_stack[-5:], ast.AST.Sub)
+ ]
+ )
+ ]
+ $$ = $1 - $3
+ }
+ | E '*' E {
+ yy_element_stack[-5:] = [
+ element.Element(
+ 'root',
+ children = [
+ element.concatenate(yy_element_stack[-5:], ast.AST.Mul)
+ ]
+ )
+ ]
+ $$ = $1 * $3
+ }
+ | E '/' E {
+ yy_element_stack[-5:] = [
+ element.Element(
+ 'root',
+ children = [
+ element.concatenate(yy_element_stack[-5:], ast.AST.Div)
+ ]
+ )
+ ]
+ $$ = $1 / $3
+ }
+ | '(' E ')' {
+ $$ = $2
+ }
+ | '-' E %prec UMINUS {
+ $$ = -$2
+ yy_element_stack[-3:] = [
+ element.Element(
+ 'root',
+ children = [
+ element.concatenate(yy_element_stack[-3:], ast.AST.Neg)
+ ]
+ )
+ ]
+ }
| NUM
;
%%
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
+def concatenate(children, factory = Element, *args, **kwargs):
+ root = factory(*args, **kwargs)
+ for child in children:
+ i = len(root)
+ set_text(root, i, get_text(root, i) + get_text(child, 0))
+ root[i:] = child[:]
+ return root