Erlang中的符号算术

时间:2013-09-01 10:52:19

标签: parsing erlang symbolic-math

以下是O'Reilly Erlang书中的练习:

构建一组操作算术表达式的函数。从表达式开始,如下所示:

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

完全括号,并使用波浪号(〜)表示一元减号。

首先,为这些编写解析器,将它们转换为Erlang表示形式,例如 以下内容:

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

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

我该怎么做?

2 个答案:

答案 0 :(得分: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}.

答案 1 :(得分:1)

您可以查看我的代码以获取灵感: https://github.com/pichi/epexercises/blob/master/Exercise3-8/e38.erl它使用手写的词法分析器和解析器。还有编译器来堆栈机器代码和堆栈机器模拟器。