我想要一个简单的程序来帮助我在C语言中使用运算符优先级。最困难的部分是括号表达式。例如,我想要这个:
*a.x++ = *b.x++
转换为:
((*(((a).(x))++)) = (*(((b).(x))++)))
我在这些步骤中手动完成了这项工作:
*a.x++ = *b.x++
*(a).(x)++ = *(b).(x)++
*((a).(x))++ = *((b).(x))++
*(((a).(x))++) = *(((b).(x))++)
(*(((a).(x))++)) = (*(((b).(x))++))
((*(((a).(x))++)) = (*(((b).(x))++)))
以编程方式完成此操作的最佳方法是什么?我可以使用的解决方案吗?我更喜欢在PHP,C,C ++,Python或Ruby中执行此操作。
(这不是我的计划的全部想法,这只是第一步。)
答案 0 :(得分:6)
您将需要某种能够理解运算符优先级的解析器。 C的常用版本是Lexx / Yacc或flex / bison,最简单的方法是构造一个解析树。完成后,只需按照“预购”顺序浏览解析树,并在进入和离开节点时发出parens。
答案 1 :(得分:4)
最可靠的方法是parse the expression(当然要考虑precedence rules),然后以自上而下的方式处理生成的AST(抽象语法树),为您添加括号继续前进
答案 2 :(得分:3)
如何转换为后缀和评估。 如果以下方法有效,您能试试吗? 让我们拿* a.x ++
Operator Precedence Arguments Needed
. 3 2
++ 2 1
* 1 1
所以现在将表达式转换为后缀表示法。这应该给你
a x . ++ *
现在对postfix的评估就像将事物推入堆栈一样简单,当你点击运算符时,弹出顶部n(运算符需要)元素并将它们作为参数传递,将结果存储回堆栈。 在您的情况下,您将返回操作的文本表示
,而不是评估 Stack
Read a a
Read x x
Read . (a.x)
Read ++ ((a.x)++)
Read * (*((a.x)++))
如果有帮助,您可能需要查看:
http://www.spsu.edu/cs/faculty/bbrown/web_lectures/postfix/
Bart de smet's DynCalc series of posts
My attempt at TDDing a similar solution
答案 3 :(得分:2)
您可以从运算符创建二进制表达式树。
我相信有几种算法可以在线创建这样的树。
我能想到的一个简单方法是通过优先级对运算符进行排序,然后由首先执行优先级最低的运算符将字符串拆分为2部分,然后继续递归地将其他2个部分反复拆分,然后最终,你将以二叉树形式表达。
然后当你有二进制树形式的表达式时,你可以从树的树叶“括起来”直到根。
当然,你可以通过yacc / bison编译一个完整的解析器。
答案 4 :(得分:2)
只需选择所选语言的解析器,例如C parser,解析表达式/源代码并以您希望的方式打印AST。
test.c的:
void main(void){
int c = 2;
}
终端:
$ python
>>> import pycparser
>>> test = pycparser.parse_file('test.c')
>>> test.show()
FileAST:
FuncDef:
Decl: main, [], []
FuncDecl:
ParamList:
Typename: []
TypeDecl: None, []
IdentifierType: ['void']
TypeDecl: main, []
IdentifierType: ['void']
Compound:
Decl: c, [], []
TypeDecl: c, []
IdentifierType: ['int']
Constant: int, 2
>>> for node in test.ext:
... print node
...
<pycparser.c_ast.FuncDef object at 0x7fe1436db750>
>>>
答案 5 :(得分:1)
举个简单的例子:
Exp = Term | Exp, AddOp, Term
Term = Factor | Term, MulOp, Factor
Factor = Number | Ident | PreOp, Factor | (, Exp, ) | Factor, PostOp
您可以使用语法编写翻译:
Exp = Term -> Term
| Exp, AddOp, Term -> (, Exp, AddOp, Term, )
Term = Factor -> Factor
| Term, MulOp, Factor -> (, Term, MulOp, Factor, )
Factor = Number -> Number
| Ident -> Ident
| PreOp, Factor -> (, PreOp, Factor, )
| (, Exp, ) -> (, Exp, )
| Factor, PostOp -> (, Factor, PostOp, )
在哪种情况下:
a-- + b * (a+b)
转换为:
((a--) + (b * ((a+b))))
答案 6 :(得分:1)
解析是一个很大的话题。由于您只是想用它来解决特定问题,因此尽量不要沉浸在人们所建议的所有这些特定解析算法中。相反,有许多解析器生成器,例如鹿角或野牛,它们在给定适当的语法的情况下,将解析文本并允许您对组件执行编程操作 - 例如在它们周围放置括号。其中一些系统带有C语法,或者有这样的语法。
antlr可以使用您提到的任何语言生成解析器;见http://www.antlr.org/
答案 7 :(得分:1)
您可以在旧的net.sources新闻组的档案中找到“cparen”。
如果你搜索(谷歌)'cparen',你会得到太多的噪音,但如果你搜索 对于net.sources和'cparen.c',它使搜索范围变得足够有用。
这是一个网站:
http://www.megalextoria.com/usenet-archive/news005f3/b14/net/sources/00000360.html
正如我所料,它不是一个shell存档。 它看起来像一个纯ASCII文本tar文件。 你可以只有足够的文件 用手打开包装。
答案 8 :(得分:1)
我在Python中编写了一个程序来括起表达式字符串。
def pref(op):
print "called with op", op
ret = -1
if op == '+':
print "matched +"
ret = 1
if op == '-':
print "matched -"
ret = 2
if op == '*':
print "matched *"
ret = 3
if op == '/':
print "matched /"
ret = 4
return ret
def evaluate(expr, operand_stack, operator_stack):
print "**In evaluate**"
print operator_stack
print operand_stack
expr1 = operand_stack.pop()
expr2 = operand_stack.pop()
op = operator_stack.pop()
# Parenthesize the expression
expr = "(" + expr2 + op + expr1 + ")"
print "expr1", expr1
print "expr2", expr2
print "expr", expr
# Push the result back on the stack
operand_stack.append(expr)
print operator_stack
print operand_stack
print "**Out evaluate**"
return expr
def looper(str, expr, operator_stack, operand_stack):
l = 0
cnt = len(str)
# Loop over the input string
while l < cnt:
if str[l] in ('+', '-', '*', '/'):
print "operator found: op, index", str[l], l
print operator_stack, len(operator_stack)
x = len(operator_stack) - 1
if x > 0:
print "Comparing:", operator_stack[x], str[l]
# If op on stack has higher preference than the op in question
if (pref(operator_stack[x]) > pref(str[l])):
expr = evaluate(expr, operand_stack, operator_stack)
operator_stack.append(str[l])
else:
# Add the operand to operand stack
operand_stack.append(str[l])
l += 1
print operator_stack
print operand_stack
print "Take care of last elements"
op_cnt = len(operator_stack)
while op_cnt:
expr = evaluate(expr, operand_stack, operator_stack)
op_cnt -= 1
print operator_stack
print operand_stack
if __name__ == '__main__':
str = "a+c*d-e/w*x+a-s"
cnt = len(str)
operand_stack = []
operator_stack = []
expr = ""
looper(str, expr, operator_stack, operand_stack)
print "Output=>", operand_stack[0]
答案 9 :(得分:0)
有一个非常古老的(1980年代)开源程序正是这样做的。 它被称为“cparen”,但如果我能在网上找到它,我该死的。只有热情提及它,例如 https://groups.google.com/group/comp.lang.c/tree/browse_frm/month/1990-03/1583b4728a6d94db http://www.language-c.info/re-should-i-capitalize-const-identifiers
如果你找到它比我更幸运,请写下