如何为表达式添加括号?

发布于 2024-07-13 19:59:40 字数 562 浏览 14 评论 0原文

我有一个想法,可以制作一个简单的程序,它将帮助我处理 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 来完成此操作。

(这不是我的程序的全部想法,这只是第一步。)

I have an idea for a simple program to make that will help me with operator precedence in languages like C. The most difficult part of this is parenthesizing the expression. For example, I want this:

*a.x++ = *b.x++

Converted to this:

((*(((a).(x))++)) = (*(((b).(x))++)))

Which I did manually in these steps:

           *a.x++ = *b.x++
       *(a).(x)++ = *(b).(x)++
     *((a).(x))++ = *((b).(x))++
   *(((a).(x))++) = *(((b).(x))++)
 (*(((a).(x))++)) = (*(((b).(x))++))
((*(((a).(x))++)) = (*(((b).(x))++)))

What is the best way to accomplish this? Is there already a solution out there that I could use? I'd prefer to do this in either PHP, C, C++, Python, or Ruby.

(This isn't the whole idea of my program, it is only the first step.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

沫离伤花 2024-07-20 19:59:41

最可靠的方法是解析表达式(考虑到account 优先级规则,当然),然后在 a 中处理生成的 AST(抽象语法树)自上而下的方式,在前进时添加括号

The most reliable way will be to parse the expression (taking into account precedence rules, of course) and then process the resulting AST (Abstract Syntax Tree) in a top-down manner, adding parenthesis as you move along

七婞 2024-07-20 19:59:41

转换为后缀并评估怎么样?
您可以尝试以下方法是否有效。
让我们以 *a.x++

Operator    Precedence  Arguments Needed
.           3               2
++          2               1
*           1               1

为例,现在将表达式转换为后缀表示法。 现在,对

a x . ++ *

后缀的评估就像将东西推入堆栈一样简单,当您点击运算符时,弹出前 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 /后缀/
Bart de smet 的 DynCalc 系列帖子
我尝试 TDD 类似的解决方案

How about converting to postfix and evaluating.
Can you try if the following approach works.
Lets take *a.x++

Operator    Precedence  Arguments Needed
.           3               2
++          2               1
*           1               1

So now convert the expression to postfix notation. This should give you

a x . ++ *

Now evaluation of postfix is as simple as pushing things into a stack, when you hit an operator, pop the top n (as needed by operator) elements and pass them as arguments, store results back onto the stack.
In your case, instead of evaluating, you'd return a textual representation of the operation

        Stack
Read a      a
Read x      x
Read .      (a.x)
Read ++     ((a.x)++)
Read *      (*((a.x)++))

if it helps, you may want to look at:
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

波浪屿的海角声 2024-07-20 19:59:41

只需选择适合您所选语言的解析器,例如 C 解析器,解析表达式/源代码并以您想要的方式打印 AST。

测试.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>
>>>

Just pick up a parser for your selected language, for instance C parser, parse the expression/source code and print the AST back in the way you want.

test.c:

void main(void){
    int c = 2;
}

terminal:

$ 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>
>>>
水中月 2024-07-20 19:59:41

您可以从运算符创建二叉表达式树。

我相信网上已经有几种算法可以创建这样的树。

我能想到的一种简单方法是按优先级对运算符进行排序,然后首先按优先级最低的运算符将字符串分成两部分,然后继续递归地一遍又一遍地向下拆分其他两部分,最后,你将会有二叉树形式的表达式。

然后,当您拥有二叉树形式的表达式时,您可以从树的叶子到根“加括号”。

当然,您可以通过 yacc/bison 编译一个成熟的解析器。

You could create a binary expression tree from the operators.

I believe there are several algorithms available online to create such tree already.

One simple way I could think of, is by sorting the operator by precedence, and then split the string into 2 parts by the operator with the lowest precedence first, then continue recursively splitting the other 2 parts down over and over and then eventually, you'll have the expression in binary tree form.

And then when you have the expression in binary tree form, you can then "parenthesize" up from the tree's leaves up to the root.

And of course, you could compile a full-fledged parser via yacc/bison.

高跟鞋的旋律 2024-07-20 19:59:41

举一个简单的例子:

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))))

As a simple example:

Exp = Term | Exp, AddOp, Term 
Term = Factor | Term, MulOp, Factor
Factor = Number | Ident | PreOp, Factor | (, Exp, ) | Factor, PostOp

You can uses the grammar to write the translations:

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, )

In which case:

a-- + b * (a+b) 

Translates to:

((a--) + (b * ((a+b))))
故人爱我别走 2024-07-20 19:59:41

解析是一个很大的话题。 由于您只是想用它来解决特定问题,因此请尽量不要沉浸在人们建议的所有这些特定解析算法中。 相反,有许多解析器生成器,例如 antler 或 bison,在给定适当的语法的情况下,它们将解析文本并允许您对组件执行编程操作 - 例如在它们周围添加括号。 其中一些系统附带了 C 语法,或者具有可用的此类语法。

antlr 可以生成您提到的任何语言的解析器; 请参阅http://www.antlr.org/

Parsing is a huge topic. Since you just want to use it to solve a specific problem, try not to get immersed in all these specific parsing algorithms that people are suggesting. Rather, there are numerous parser generators, such as antler or bison which, given an appropriate grammar, will parse text and allow you to perform programmatic operations on the components -- such as put parentheses around them. Some of these systems come with grammars for C, or have such grammars available.

antlr can generate parsers in any of the languages you mentioned; see http://www.antlr.org/

表情可笑 2024-07-20 19:59:41

您可以在旧的 net.sources 新闻组的档案中找到“cparen”。

如果您搜索(Google)“cparen”,您会得到太多噪音,但如果您搜索
对于 net.sources 和 'cparen.c',它缩小了搜索范围,足以发挥作用。

这是一个网站:

http://www.megalextoria。 com/usenet-archive/news005f3/b14/net/sources/00000360.html

正如我所期望的那样,它不是一个 shell 存档。
它看起来像一个纯 ASCII 文本 tar 文件。
文件数量足够少,您可以
用手拆开包装。

You can find "cparen" in the archives of the old net.sources newsgroup.

If you search (Google) for 'cparen', you get too much noise, but if you search
for net.sources and 'cparen.c' that narrows the search enough to be useful.

Here is one website:

http://www.megalextoria.com/usenet-archive/news005f3/b14/net/sources/00000360.html

It is not a shell archive, as I would have expected.
It looks like a pure ASCII text tar file.
There are few enough files that you could just
unpack it by hand.

原来是傀儡 2024-07-20 19:59:41

我用 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]

I wrote a program in Python to parenthesize an expression string.

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]
凡尘雨 2024-07-20 19:59:41

有一个非常古老的(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

如果你比我更幸运地找到它,请写

There is a very old (1980's) open source program to do exactly this.
It's called "cparen", but I'm damned if I can find it on the net. Only enthusiastic mentions of it, e.g.
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

If you have more luck than me in finding it, do write

扛起拖把扫天下 2024-07-20 19:59:40

您将需要某种能够理解运算符优先级的解析器。 C 的常用版本是 Lexx/Yacc 或 flex/bison,最简单的方法是构造一个解析树。 完成此操作后,只需按“预序”顺序遍历解析树,并在进入和离开节点时发出括号。

You're going to need a parser of some sort that understands operator precendence. The usual version for C is Lexx/Yacc or flex/bison, and the easiest way to do it is construct a parse tree. Once you've done that, just walk the parse tree in the "preorder" order and emit parens as you enter and leave a node.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文