Chinaunix首页 | 论坛 | 博客
  • 博客访问: 101610
  • 博文数量: 18
  • 博客积分: 681
  • 博客等级: 中士
  • 技术积分: 295
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-17 13:33
文章分类
文章存档

2012年(8)

2011年(10)

分类: Python/Ruby

2011-11-30 19:47:41

最近在学Erlang,就使用Erlang写了个算数表达式的解析器,该解析器仅支持加减乘除和括号运算,下面为几个表达式对应的输出。
  1. 1 -> {num,1}
  2. 1+2 -> {plus,{num,1},{num,2}}
  3. 1+2*3 -> {plus,{num,1},{multi,{num,2},{num,3}}
  4. (1+2)*3-> {multi,{plus,{num,1},{num,2}},{num,3}}
  5. 3/3/3->{div,{num,3},{div,{num,3},{num,3}}}
从某本编译器上的书上得到表达式的语法规则如下:
  1. expr -> term | term addop expr
  2. addop -> + | -
  3. term -> factor | factor mulop term
  4. mulop -> * | /
  5. factor -> NUM | (expr)
根据语法规则很容易使用递归下降分析法写出解析器,程序代码如下:

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

%% Syntax Grammer
%% expr -> term | term + expr | term - expr
%% term -> factor | factor * term | factor / term
%% factor -> NUM | (expr)

parse(Tokens) ->
    element(1, expr(Tokens)).

expr(Tokens) ->
    {LeftTree, RestTokens} = term(Tokens),
    if 
length(RestTokens) == 0 -> 
   {LeftTree, []};
true -> 
   [Head | Tail] = RestTokens,
   {Lt, Rt} = expr(Tail),
   case Head of
$+ -> {{plus, LeftTree, Lt}, Rt};
$- -> {{sub, LeftTree, Lt}, Rt};
_Other -> {LeftTree, RestTokens}
   end
    end.

term(Tokens) ->
    {LeftTree, RestTokens} = factor(Tokens),
    if 
length(RestTokens) == 0 ->
   {LeftTree, []};
true -> [Head | Tail] = RestTokens,
{LT, Rt} = term(Tail),
case Head of
    $* -> {{multi, LeftTree, LT}, Rt};
    $/ -> {{divide, LeftTree, LT}, Rt};
    _Other -> {LeftTree, RestTokens}
end
    end.

factor([]) ->
    {{}, []};
factor([Head | Tail]) ->
    if 
Head >= $0, Head =< $9 -> 
   {Int, Rest} = string:to_integer([Head | Tail]),
   {{num, Int}, Rest};
Head == $( -> 
   {Lt, Rt} = expr(Tail),
   is_match(Rt, $)),
   [_ | T] = Rt,
   {Lt, T};
true ->
   {{}, [Head | Tail]}
    end.

    
is_match([Token | _], Token) ->
    ok;
is_match(_, _) ->
    throw ({'EXIT', "unexpected token"}).

问题一:该语法规则怎么体现运算符的优先级的,如为什么乘除的优先级高于加减?
expr->term addop expr
term->factor mulop term
addop对应的规则在mulop前面。根据语法规则,在expr函数内部首先会调用term,然后调用factor,当碰到终结符时,函数调用回回溯到factor。此时会判断当前token是否为mulop,只有当前token不是为mulop,才会向上再回溯到expr,然后判断是否为addop。因此,乘除的优先级就高于加减。

问题二:运算符的结合性(向左结合/向右结合)是如何体现的。
term->factor mulop term,这是个递归调用,只有当term解析完毕后,才回回到factor mulop term的解析过程中,而term已经分析完成一部分代码了,因此3/3/3会得到{div,{num,3},{div,{num,3},{num,3}}},也就是乘除运算符是向右结合。
阅读(1977) | 评论(0) | 转发(0) |
0

上一篇:位排序

下一篇:进程环

给主人留下些什么吧!~~