Ecco un modo per farlo che abusa del parser integrato per i termini di Erlang. Potresti scrivere il tuo parser tramite yecc o discesa ricorsiva, ma per la semplicità rimarrò con il parser di Erlang.
-module(foo).
-compile(export_all).
Dichiarare un modulo, esportare tutto da esso. Questa è una brutta forma se vuoi usarla. Piuttosto, ridurre l'esportazione a p/1
.
parse(Str) ->
{ok, Tokens, _} = erl_scan:string(Str ++ "."),
{ok, [E]} = erl_parse:parse_exprs(Tokens),
E.
Questa funzione abusi del parser Erlang in modo che possiamo ottenere un albero sintattico di gettoni Erlang.
rpn({op, _, What, LS, RS}) ->
rpn(LS),
rpn(RS),
io:format(" ~s ", [atom_to_list(What)]);
rpn({integer, _, N}) ->
io:format(" ~B ", [N]).
L'uscita RPN deve eseguire una traversata dell'albero-marcia post-ordine. Quindi, fondamentalmente camminiamo sulla mano sinistra e sul lato destro dell'albero e quindi emettiamo noi stessi come un nodo. L'ordine di "parentesi" è memorizzato in modo astratto nell'albero stesso. La priorità è gestita dal parser di Erlang. Si potrebbe facilmente farlo tramite un parser di discesa ricorsiva, se lo si desidera. Ma questa è una domanda diversa al punto "Come scrivere i parser in Erlang?" La risposta è duplice: o usi leex + yecc o usi un parser basato su combinatori di parser e/o discesa ricorsiva. Soprattutto per una grammatica così semplice.
p(Str) ->
Tree = parse(Str),
rpn(Tree),
io:format("~n").
Questa è solo la formattazione.
Non vedo la logica di trattare con priorità lì .. –
Come ho accennato, la priorità è gestita da un parser. È davvero separato dalla domanda "Come faccio a formattare un albero di analisi in notazione RPN", che è ciò che fa sopra. Puoi cercare la discesa ricorsiva che è un modo per farlo per una grammatica LL (1) che sono le tue espressioni. –
Ho bisogno di avere molti operatori aggiuntivi che non esistono in erlang, quindi ho bisogno di specificare la priorità manualmente, non le impostazioni predefinite di erlang. –