Domanda

Ho un'idea per un semplice programma di fare che mi aiuterà con la precedenza degli operatori in linguaggi come C. La parte più difficile di questo è mettere tra parentesi l'espressione. Per esempio, io voglio questo:

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

Convertito a questa:

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

Cosa che ho fatto manualmente in questi passaggi:

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

Qual è il modo migliore per ottenere questo livello di codice? C'è già una soluzione là fuori che potrei usare? Preferirei farlo in entrambi i PHP, C, C ++, Python o Ruby.

(Questo non è l'idea del mio programma, è solo il primo passo.)

È stato utile?

Soluzione

Basta prendere un parser per la lingua selezionata, per esempio C parser , analizzare il / codice sorgente espressione e di stampa sul retro AST nel modo desiderato.

test.c:

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

terminale:

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

Altri suggerimenti

Si sta andando ad avere bisogno di un parser di qualche tipo che capisce operatore precendenza. La versione usuale per C è Lexx / Yacc o Flex / Bison, e il modo più semplice per farlo è costruire un albero sintattico. Una volta fatto questo, solo a piedi l'albero sintattico nell'ordine "preorder" ed emettono parentesi come si entra e lasciare un nodo.

Il modo più affidabile sarà a analizzare l'espressione (tenendo conto regole di precedenza , ovviamente) e quindi elaborare l'AST risultante (Abstract Syntax Tree ) in modo top-down, l'aggiunta di parentesi come ci si sposta lungo

Come sulla conversione per postfix e valutare. Si può provare se il seguente approccio funziona. Consente di prendere * a.x ++

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

Così ora convertire l'espressione in notazione postfissa. Questo dovrebbe dare

a x . ++ *

Ora la valutazione di postfix è semplice come premere le cose in una pila, quando si colpisce un operatore, pop cima n (se necessario dall'operatore) elementi e li passano come argomenti, risultati negozio di nuovo in cima alla pila. Nel tuo caso, invece di valutare, che ci si ritorni una rappresentazione testuale del funzionamento

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

se ti aiuta, si consiglia di guardare in:
http://www.spsu.edu/cs/faculty/bbrown/web_lectures / postfix /
serie DynCalc di Bart de Smet dei messaggi
Il mio tentativo di TDDing una soluzione simile

È possibile creare un albero di espressione binario da parte degli operatori.

Credo che ci sono diversi algoritmi disponibili on-line per creare già ad albero.

Un modo semplice ho potuto pensare, è di classificare l'operatore di precedenza, e quindi dividere la stringa in 2 parti dall'operatore con la precedenza più basso prima, per poi proseguire in modo ricorsivo dividere le altre 2 parti giù più e più volte e poi alla fine, avrete l'espressione in forma di albero binario.

E poi, quando si ha l'espressione in forma di albero binario, è quindi possibile "parenthesize" dal foglie dell'albero fino alla radice.

E, naturalmente, si potrebbe compilare un parser a tutti gli effetti tramite Yacc / bisonti.

Come semplice esempio:

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

È possibile utilizza la grammatica di scrivere le traduzioni:

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 questo caso:

a-- + b * (a+b) 

si traduce in:

((a--) + (b * ((a+b))))

parsing è un argomento enorme. Dal momento che si desidera utilizzare per risolvere un problema specifico, cercare di non immergersi in tutti questi algoritmi di analisi specifiche che le persone stanno suggerendo. Piuttosto, ci sono numerosi generatori di parser, come corna o di bisonti che, data una grammatica del caso, sarà analizzare il testo e consentono di eseguire operazioni programmatiche sui componenti - come il put parentesi intorno a loro. Alcuni di questi sistemi sono dotati di grammatiche per C, o avere tali grammatiche disponibili.

ANTLR in grado di generare parser in una qualsiasi delle lingue che hai citato; vedi http://www.antlr.org/

Si possono trovare "cparen" negli archivi della vecchia net.sources newsgroup.

Se si esegue una ricerca (Google) per 'cparen', si ottiene troppo rumore, ma se si cerca per net.sources e 'cparen.c' che restringe la ricerca abbastanza per essere utile.

Ecco un sito web:

http://www.megalextoria.com/ usenet-archive / news005f3 / B14 / net / fonti / 00000360.html

Non è un archivio di shell, come mi sarei aspettato. Si presenta come un file tar di testo ASCII puro. Ci sono pochi file abbastanza che si poteva solo scompattarlo a mano.

ho scritto un programma in Python mettere tra parentesi una stringa di espressione.

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]

C'è un vecchio (1980) programma open source per fare esattamente questo. Si chiama "cparen", ma che io sia dannato se riesco a trovarlo in rete. Solo entusiasta menzioni di esso, ad esempio, 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

Se avete più fortuna di me a trovarlo, scriva

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top