我希望能够构建和修改一个ast然后可选地将其写为python字节代码,以便以后执行而无需开销.
我一直在黑客与周围的AST文档为python3.0和python2.6,但我似乎无法找到对这种类型的代码的最佳实践任何的良好来源.
在python中修改抽象语法树有哪些最佳实践和指南?
// Create a scanner that reads from the input stream passed to us
CSLexer lexer = new CSLexer(new ANTLRFileStream(f));
tokens.TokenSource = lexer;
// Create a parser that reads from the scanner
CSParser parser = new CSParser(tokens);
// start parsing at the compilationUnit rule
CSParser.compilation_unit_return x = parser.compilation_unit();
object ast = x.Tree;
Run Code Online (Sandbox Code Playgroud)
我怎么能用compilation_unit_return类型的x来提取它的根,它的类,它的方法等?我必须提取其适配器吗?我怎么做?请注意,compilation_unit_return在我的CSParser中定义(由ANTLR自动生成):
public class compilation_unit_return : ParserRuleReturnScope
{
private object tree;
override public object Tree
{
get { return tree; }
set { tree = (object) value; }
}
}; …Run Code Online (Sandbox Code Playgroud) 更新接受了Ira Baxter的回答,因为它指出了我正确的方向:我首先通过开始编译阶段的实现来弄清楚我实际需要什么,很明显很快,节点内的遍历使得这是一个不可能的方法.并非所有节点都应该被访问,其中一些节点的顺序相反(例如,首先是赋值的rhs,因此编译器可以检查类型是否与rhs /运算符匹配).在访问者中进行遍历使得这一切变得非常简单.
在决定对应用程序中使用的迷你语言的处理进行重大修改之前,我正在玩AST和类似的东西.我已经构建了一个Lexer/Parser,可以让AST很好.还有一个访问者,作为具体实现,我创建了一个ASTToOriginal,它只是重新创建原始源文件.最终,还有一些编译器也可以实现Vsisitor并在运行时创建实际的C++代码,所以我想确保一切从一开始就是正确的.虽然现在一切正常,但由于遍历顺序在访问者本身中实现,因此存在一些相似/重复的代码.
在查找更多信息时,似乎某些实现更喜欢在访问对象本身中保留遍历顺序,以便不在每个具体访问者中重复此操作.即便是GoF也只是以同样的方式对此进行了简要的讨论.所以我想尝试这种方法,但很快就陷入了困境.让我解释一下.
示例源代码行和相应的AST节点:
if(t>100?x=1;sety(20,true):x=2)
Conditional
BinaryOp
left=Variable [name=t], operator=[>], right=Integer [value=100]
IfTrue
Assignment
left=Variable [name=x], operator=[=], right=Integer [value=1]
Method
MethodName [name=sety], Arguments( Integer [value=20], Boolean [value=true] )
IfFalse
Assignment
left=Variable [name=x], operator=[=], right=Integer [value=1]
Run Code Online (Sandbox Code Playgroud)
一些代码:
class BinaryOp {
void Accept( Visitor* v ){ v->Visit( this ); }
Expr* left;
Op* op;
Expr* right;
};
class Variable {
void Accept( Visitor* v ){ v->Visit( this ); }
Name* name;
};
class Visitor { //provide basic traversal, terminal …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用deepcopy(从copy模块)深度复制模块中的节点树ast.
这似乎不起作用.我遇到了奇怪的错误,比如TypeError: required field "name" missing from FunctionDef当我使用复制的结果时(我检查了它;它在复制的节点中确实丢失了),所以它没有正确地复制它们.
有什么技巧可以使这个工作吗?或许我错过了什么?
原始问题:
在python Web服务器上执行数学用户代码,最简单的安全方法是什么?
由于需要Python的一小部分,我目前的方法是通过遍历Python的抽象语法树将允许的语法列入白名单.功能和名称得到特殊待遇; 只允许明确列入白名单的函数,并且只允许使用未使用的名称.
import ast
allowed_functions = set([
#math library
'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh',
'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf',
'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod',
'frexp', 'fsum', 'gamma', 'hypot', 'isinf', 'isnan', 'ldexp',
'lgamma', 'log', 'log10', 'log1p', 'modf', 'pi', 'pow', 'radians',
'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc',
#builtins
'abs', 'max', 'min', 'range', 'xrange'
])
allowed_node_types = set([
#Meta
'Module', 'Assign', 'Expr',
#Control
'For', 'If', 'Else',
#Data
'Store', 'Load', 'AugAssign', 'Subscript',
#Datatypes …Run Code Online (Sandbox Code Playgroud) 我目前正在开发一个玩具函数式语言编译器,目的是学习与Haskell中类型相关的东西和稍微先进的技术.
我相信我需要将信息附加到我树上的每个节点,比如原始源代码中的位置,以便更好地报告错误,输入类型,生成类型约束等等.所以最初我选择了这个方法:
data Expr a = ELam [Pat a] (Expr a) a
| ELet [Decl a] (Expr a) a
| EIf (Expr a) (Expr a) (Expr a) a
| ECase (Expr a) [Alt a] a
| EApp (Expr a) [Expr a] a
| EVar Variable a
| ECon Variable a
| ELit Literal a
| ELOpSec (Op a) (Expr a) a
| EROpSec (Op a) (Expr a) a
| EInfix (Expr a) (Op a) (Expr a) a
| ENeg (Expr …Run Code Online (Sandbox Code Playgroud) 以下问题
并且他们各自的答案让我想到我如何能够有效地解析一个(或多或少可信的)用户给出的单个数学表达式(一般来说,就这个答案而言)/sf/answers/41600611/来自数据库的20k到30k输入值.我实施了快速而肮脏的基准测试,因此我可以比较不同的解
# Runs with Python 3(.4)
import pprint
import time
# This is what I have
userinput_function = '5*(1-(x*0.1))' # String - numbers should be handled as floats
demo_len = 20000 # Parameter for benchmark (20k to 30k in real life)
print_results = False
# Some database, represented by an array of dicts (simplified for this example)
database_xy = []
for a in range(1, demo_len, 1):
database_xy.append({
'x':float(a),
'y_eval':0,
'y_sympya':0,
'y_sympyb':0,
'y_sympyc':0,
'y_aevala':0, …Run Code Online (Sandbox Code Playgroud) 我试图在没有任何花哨库(即从头开始)的帮助下在C中构建一个迷你Bash解释器.我必须管理简单的运算符,如'<','|','<<','>>','>'.
我被告知要构建输入的AST以便于执行过程.问题是,我不明白我应该如何构建一个.
到目前为止,我制作了一个链接列表,我的输入变成了令牌,但无法想出如何制作AST:
typedef struct s_token
{
enum e_TokenType type;
char *lexeme;
struct s_token *prev;
struct s_token *next;
} t_token;
Run Code Online (Sandbox Code Playgroud)
你能解释一下如何把它变成一个功能AST吗?例如,使用此输入:
cat << EOF > file | wc -c | tr -d " " > file2
Run Code Online (Sandbox Code Playgroud)
我想AST会是这样的:

我已经看到其他帖子描述了如何但他们在JS/Python(我不熟悉这些语言)和使用库感兴趣的部分.
比方说,我有一堆的功能a,b,c,d和e我想看看他们是否直接使用一个循环:
def a():
for i in range(3):
print(i**2)
def b():
i = 0
while i < 3:
print(i**2)
i += 1
def c():
print("\n".join([str(i**2) for i in range(3)]))
def d():
print("\n".join(["0", "1", "4"]))
def e():
"for"
Run Code Online (Sandbox Code Playgroud)
我想写一个函数,uses_loop所以我可以期望这些断言传递:
assert uses_loop(a) == True
assert uses_loop(b) == True
assert uses_loop(c) == False
assert uses_loop(d) == False
assert uses_loop(e) == False
Run Code Online (Sandbox Code Playgroud)
(我希望uses_loop(c)返回,False因为c使用列表解析而不是循环.)
我不能修改a,b …