2009-02-14 29 views
3

我有一個簡單的程序的想法,這將幫助我像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

你說這只是程序的第一步 - 你_actually_需要括號添加到表達式中的文本表示,或者你只需​​要構建一個AST(的一個內存中表示表達)? – 2011-11-02 23:34:04

回答

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

你會需要某種能理解運營商precendence的解析器。 C的常用版本是Lexx/Yacc或flex/bison,最簡單的方法是構造一個分析樹。一旦你完成了這些,只需按照「預先訂購」順序步行解析樹,並在進入和離開節點時發出parens。

4

最可靠的方法將是parse the expression(考慮到precedence rules,當然),然後處理在自上而下的方式所產生的AST(抽象語法樹),加入括號當你沿着

2

您移動可以從操作符創建二進制表達式樹。

我相信有幾種算法可以在線創建這樣的樹。

我能想到的一種簡單方法是按優先順序對運算符進行排序,然後先由具有最低優先級的運算符將字符串拆分爲2個部分,然後繼續遞歸地將其他2個部分分割並重復,那麼最終你會以二叉樹的形式表達。

然後,當你用二叉樹形式表達時,你可以從樹的葉子向上「加圓括號」直到根。

當然,你可以通過yacc/bison編譯一個完整的解析器。

3

如何轉換爲後綴和評估。 如果以下方法有效,您可以嘗試嗎? 讓我們* 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/postfix/
Bart de smet's DynCalc series of posts
My attempt at TDDing a similar solution

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

解析是一個很大的話題。既然你只是想用它來解決一個特定的問題,儘量不要沉浸在人們建議的所有這些特定的解析算法中。相反,有許多解析器生成器,比如鹿角或野牛,在給定適當語法的情況下,它將解析文本並允許您對組件執行編程操作 - 比如在它們周圍放置括號。這些系統中的一些爲C語言提供了語法,或者有這樣的語法可用。

antlr可以用您提到的任何語言生成解析器;請參閱http://www.antlr.org/

1

你可以找到舊網絡資源新聞組檔案中的「cparen」。

如果您搜索'cparen',會得到太多噪音,但是如果您搜索 來搜索net.sources和'cparen.c',這會縮小搜索範圍,從而有用。

這裏是一個網站:

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

它不是一個shell歸檔,因爲我本來期望。 它看起來像一個純粹的ASCII文本tar文件。 只有很少的文件可以用 手動解壓。

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] 
相關問題