2013-09-01 80 views
3

以下是O'Reilly Erlang書中的練習:Erlang中的符號算術

構建操作算術表達式的函數的集合。與表達開始,如以下幾點:

(~((2*3)+(3*4)))

這是完全括號並在您使用一元減一個符號(〜)。

首先,寫這些解析器,把它們變成二郎表示,如 如下:

{minus, {plus, {num, 2}, {num,3}}, {num, 4}}

代表((2+3)-4) ...

我怎樣才能做到這一點?

+0

+1學習Erlang。 – Jason

回答

3

那麼,你是如何做到這一點取決於你想要什麼樣的解析器。最簡單的方法可能是使用類似yeccneotoma的東西來爲此語言生成解析器。

如果您試圖手動編寫解析器,那肯定是可行的。這裏是你會如何開始寫一個:

-module(parser). 
-export([parse/1]). 

%% parser:parse("((2+3)+4)") =:= {plus, {plus, {num, 2}, {num, 3}}, {num, 4}}. 

parse(S) -> 
    {[Expr], ""} = parse(S, expr, []), 
    Expr. 

-define(IS_DIGIT(C), (C >= $0 andalso C =< $9)). 
-define(IS_SPACE(C), 
     (C =:= $\s orelse C =:= $\t orelse C =:= $\r orelse C =:= $\n)). 
is_space(C) -> 
    ?IS_SPACE(C). 
is_digit(C) -> 
    ?IS_DIGIT(C). 

skip_space(S) -> 
    lists:dropwhile(fun is_space/1, S). 

parse([$(| Rest], expr, []) -> 
    {[Expr], Rest1} = parse(Rest, expr, []), 
    [$) | Rest2] = skip_space(Rest1), 
    parse(Rest2, op, [Expr]); 
parse(S=[D | _], expr, []) when ?IS_DIGIT(D) -> 
    {Ds, Rest1} = lists:splitwith(fun is_digit/1, S), 
    parse(Rest1, op, [{num, list_to_integer(Ds)}]); 
parse([$+ | Rest], op, [Left]) -> 
    {[Right], Rest1} = parse(Rest, expr, []), 
    {[{plus, Left, Right}], Rest1}; 
parse([C|Rest], State, Acc) when ?IS_SPACE(C) -> 
    parse(skip_space(Rest), State, Acc); 
parse(S, _State, Acc) -> 
    {Acc, S}.