免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: yuanquan08
打印 上一主题 下一主题

各位大虾,小弟有难啊! [复制链接]

论坛徽章:
7
巳蛇
日期:2014-04-10 08:54:57白羊座
日期:2014-04-22 20:06:262015年亚洲杯之沙特阿拉伯
日期:2015-02-10 14:18:532015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之吉达阿赫利
日期:2015-06-02 11:34:112015亚冠之武里南联
日期:2015-06-24 12:13:082015亚冠之阿尔纳斯尔
日期:2015-08-03 09:08:25
31 [报告]
发表于 2013-12-24 13:44 |只看该作者
回复 26# felonwan

语法树不一定是二叉树,不过一般二叉树就够用了,特别是对这个例子来说。事实上用正则处理的过程本质上也是进行词法和语法分析,只不过因为没有中间建立语法树的过程,所以代码的维护和扩展会比较麻烦,毕竟词法语法和语义方面的代码全混杂在一起嘛。
   

论坛徽章:
7
巳蛇
日期:2014-04-10 08:54:57白羊座
日期:2014-04-22 20:06:262015年亚洲杯之沙特阿拉伯
日期:2015-02-10 14:18:532015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之吉达阿赫利
日期:2015-06-02 11:34:112015亚冠之武里南联
日期:2015-06-24 12:13:082015亚冠之阿尔纳斯尔
日期:2015-08-03 09:08:25
32 [报告]
发表于 2013-12-24 13:58 |只看该作者
回复 30# MMMIX

嗯,这个我赞同。如果不考虑效率的话(这个我一般最后考虑),处理一般的任务都是像Perl,Ruby之类的动态脚本语言比C简单。所以我才在这里贴出这个方案的,希望有其他人写,原本我自己没打算要给代码的,因为我自己现在工作中用不到Perl,而作为兴趣的话比起Perl我更喜欢Haskell(虽然才刚入门),所以自己写的话会用Haskell或C写,不过又不知道这个论坛的人会不会对这两种语言的实现感兴趣。像这种简单的语法分析工作,确实用手工写DFA实现就够了,不过之所以提Flex和YACC,以及Haskell的parsec,是因为使用这些工具就是熟悉这些工具的过程,然后我在其它更复杂一些的项目里就可以更加得心应手的用它们了(虽然事实上我已经使用过这些工具了,包括在公司的一个小项目上)。而,相对的,另一方面,虽然我知道纯手工写DFA实现词法和语法分析的算法,但是因为我并不是计算机相关专业毕业,所有这些都是我自学的,所以没有过什么课堂作业之类,也就从来没有真正手工写过,所以我也想尝试一次,所以在22楼我说了,如果我有时间的话,会用四种方式(原贴错打成三种了)来实现,其中就包括纯手工用C和Perl来写。

论坛徽章:
0
33 [报告]
发表于 2013-12-24 14:33 |只看该作者
顶,interact inside 和or各写一个函数

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
34 [报告]
发表于 2013-12-24 14:36 |只看该作者
Monox 发表于 2013-12-24 13:58
回复 30# MMMIX
像这种简单的语法分析工作,确实用手工写DFA实现就够了

DFA是用来做词法分析的,可是像楼主这里的表达式,哪里用得上DFA,Perl 的 split 就足够了。

论坛徽章:
7
巳蛇
日期:2014-04-10 08:54:57白羊座
日期:2014-04-22 20:06:262015年亚洲杯之沙特阿拉伯
日期:2015-02-10 14:18:532015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之吉达阿赫利
日期:2015-06-02 11:34:112015亚冠之武里南联
日期:2015-06-24 12:13:082015亚冠之阿尔纳斯尔
日期:2015-08-03 09:08:25
35 [报告]
发表于 2013-12-24 15:21 |只看该作者
回复 34# MMMIX

DFA除了可以做词法分析,也可以用来做语法分析,对LR(0)文法的分析栈,不过我还不确定楼主这个是否一定属于LR(0)文法。另外,我真用Perl写这个的话,还不确定会有什么方式进行词法分析,可能一个字符一个字符扫描,用DFA的方式来实现,也可能用正则,但是肯定不会用split,理由还是跟之前说的一样我的关注点并不是楼主问题的解(这个留给其他人了,事实上已经有很多人尝试给解了,虽然我没去具体看那些解),仅仅是出于个人兴趣用另一种更通用,可以扩展的方式来实现楼主这个问题,没准之后会被我当作一下小型语言解释器的代码框架进行修改和扩充。
   

论坛徽章:
0
36 [报告]
发表于 2013-12-24 15:29 |只看该作者
回复 35# Monox

期待楼上

   

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
37 [报告]
发表于 2013-12-24 17:18 |只看该作者
回复 35# Monox


    一般的词法分析肯定少不了逐个字符的扫描。不过在特殊情况下,例如楼主这里的表达式,split 就完全足够了。

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
38 [报告]
发表于 2013-12-24 17:19 |只看该作者
回复 1# yuanquan08


    解析表达式构造语法树,对语法树求值得出结果:

  1. #!/usr/bin/perl

  2. use strict;
  3. use warnings;

  4. use feature "switch";

  5. use Data::Dumper;

  6. my @tokens;
  7. my %operators = (
  8.         'interact'        => 1,
  9.         'inside'        => 1,
  10.         'or'                => 1,
  11. );

  12. while (my $exp = <DATA>) {
  13.         @tokens = map { $_ ? $_ : () } split(/\s*([\(\)])\s*|\s+/, $exp);
  14.         my $syn_tree = parser();

  15.         print $exp;
  16.         print Dumper($syn_tree), "\n";
  17.         print Dumper(evaluate($syn_tree)), "\n";
  18. }

  19. sub evaluate {
  20.         my $tree = shift;

  21.         if (ref($tree) ne "HASH") {
  22.                 return ($tree);
  23.         }

  24.         given ($tree->{op}) {
  25.                 when (/or/) {
  26.                         return (evaluate($tree->{left}), evaluate($tree->{right}));
  27.                 }
  28.                 when (/interact|inside/) {
  29.                         my @left = evaluate($tree->{left});
  30.                         my @right = evaluate($tree->{right});
  31.                         my @result;
  32.                         foreach my $l (@left) {
  33.                                 foreach my $r (@right) {
  34.                                         push @result, "${l}_${r}";
  35.                                 }
  36.                         }
  37.                         return @result;
  38.                 }
  39.         }
  40. }

  41. sub parser {
  42.         my ($left, $op, $right);

  43.         while (@tokens) {
  44.                 my $token = shift @tokens;
  45.                 given ($token) {
  46.                         when (is_variable($token)) {
  47.                                 if (not $left) {
  48.                                         $left = $token;
  49.                                 } elsif ($left and $op) {
  50.                                         my $node = node($op, $left, $token);
  51.                                         if (@tokens) {
  52.                                                 if ($tokens[0] =~ /\)/) {
  53.                                                         $right = $token;
  54.                                                 } else {
  55.                                                         $left = $node;
  56.                                                         $op = undef;
  57.                                                 }
  58.                                         } else {
  59.                                                 return $node;
  60.                                         }
  61.                                 } else {
  62.                                         die "Syntax error!";
  63.                                 }
  64.                         }
  65.                         when (is_operator($token)) {
  66.                                 if ($left) {
  67.                                         $op = $token;
  68.                                 } else {
  69.                                         die "Syntax error!";
  70.                                 }
  71.                         }
  72.                         when (/\(/) {
  73.                                 if (not $left) {
  74.                                         $left = parser();
  75.                                         if (not @tokens) {
  76.                                                 return $left;
  77.                                         }
  78.                                 } elsif ($left and $op) {
  79.                                         return node($op, $left, parser());
  80.                                 } else {
  81.                                         die "Syntax error!";
  82.                                 }
  83.                         }
  84.                         when (/\)/) {
  85.                                 if ($right) {
  86.                                         return node($op, $left, $right);
  87.                                 } elsif ($left and not $op) {
  88.                                         return $left;
  89.                                 }
  90.                                 else {
  91.                                         die "Syntax error!";
  92.                                 }
  93.                         }
  94.                 }
  95.         }
  96. }

  97. sub is_variable {
  98.         my $token = shift;
  99.         $token =~ /[[:upper:]]/;
  100. }

  101. sub is_operator {
  102.         my $token = shift;

  103.         $operators{$token};
  104. }

  105. sub node {
  106.         my ($op, $left, $right) = @_;
  107.         return {
  108.                 'left'        => $left,
  109.                 'op'        => $op,
  110.                 'right'        => $right,
  111.         };
  112. }


  113. __DATA__
  114. A or B
  115. A or B or C
  116. (A or B)
  117. ((A or B) or C)
  118. (A or (B or C))
  119. (A interact  ((B  or  C)  or (((D inside E) or F)  inside G)))
复制代码

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
39 [报告]
发表于 2013-12-24 17:20 |只看该作者
回复 12# yuanquan08


    添加对 not 的支持:

  1. #!/usr/bin/perl

  2. use strict;
  3. use warnings;

  4. use feature "switch";

  5. use Data::Dumper;

  6. my @tokens;
  7. my %operators = (
  8.         'interact'        => 1,
  9.         'inside'        => 1,
  10.         'or'                => 1,
  11.         'not'                => 1,
  12. );

  13. while (my $exp = <DATA>) {
  14.         @tokens = map { $_ ? $_ : () } split(/\s*([\(\)])\s*|\s+/, $exp);
  15.         my $syn_tree = parser();

  16.         print $exp;
  17.         print Dumper($syn_tree), "\n";
  18.         print Dumper(evaluate($syn_tree)), "\n";
  19. }

  20. sub evaluate {
  21.         my $tree = shift;

  22.         if (ref($tree) ne "HASH") {
  23.                 return ($tree);
  24.         }

  25.         given ($tree->{op}) {
  26.                 when (/or/) {
  27.                         return (evaluate($tree->{left}), evaluate($tree->{right}));
  28.                 }
  29.                 when (/not .+/) {
  30.                         return (evaluate($tree->{left}));
  31.                 }
  32.                 when (/interact|inside/) {
  33.                         my @left = evaluate($tree->{left});
  34.                         my @right = evaluate($tree->{right});
  35.                         my @result;
  36.                         foreach my $l (@left) {
  37.                                 foreach my $r (@right) {
  38.                                         push @result, "${l}_${r}";
  39.                                 }
  40.                         }
  41.                         return @result;
  42.                 }
  43.         }
  44. }

  45. sub parser {
  46.         my ($left, $op, $right);

  47.         while (@tokens) {
  48.                 my $token = shift @tokens;
  49.                 given ($token) {
  50.                         when (is_variable($token)) {
  51.                                 if (not $left) {
  52.                                         $left = $token;
  53.                                 } elsif ($left and $op) {
  54.                                         my $node = node($op, $left, $token);
  55.                                         if (@tokens) {
  56.                                                 if ($tokens[0] =~ /\)/) {
  57.                                                         $right = $token;
  58.                                                 } else {
  59.                                                         $left = $node;
  60.                                                         $op = undef;
  61.                                                 }
  62.                                         } else {
  63.                                                 return $node;
  64.                                         }
  65.                                 } else {
  66.                                         die "Syntax error!";
  67.                                 }
  68.                         }
  69.                         when (is_operator($token)) {
  70.                                 if ($token =~ /not/) {
  71.                                         if (@tokens and is_operator($tokens[0])) {
  72.                                                 $token = join(' ', $token, shift @tokens);
  73.                                         } else {
  74.                                                 die "Syntax error!";
  75.                                         }
  76.                                 }

  77.                                 if ($left) {
  78.                                         $op = $token;
  79.                                 } else {
  80.                                         die "Syntax error!";
  81.                                 }
  82.                         }
  83.                         when (/\(/) {
  84.                                 if (not $left) {
  85.                                         $left = parser();
  86.                                         if (not @tokens) {
  87.                                                 return $left;
  88.                                         }
  89.                                 } elsif ($left and $op) {
  90.                                         return node($op, $left, parser());
  91.                                 } else {
  92.                                         die "Syntax error!";
  93.                                 }
  94.                         }
  95.                         when (/\)/) {
  96.                                 if ($right) {
  97.                                         return node($op, $left, $right);
  98.                                 } elsif ($left and not $op) {
  99.                                         return $left;
  100.                                 }
  101.                                 else {
  102.                                         die "Syntax error!";
  103.                                 }
  104.                         }
  105.                 }
  106.         }
  107. }

  108. sub is_variable {
  109.         my $token = shift;
  110.         $token =~ /[[:upper:]]/;
  111. }

  112. sub is_operator {
  113.         my $token = shift;

  114.         $operators{$token};
  115. }

  116. sub node {
  117.         my ($op, $left, $right) = @_;
  118.         return {
  119.                 'left'        => $left,
  120.                 'op'        => $op,
  121.                 'right'        => $right,
  122.         };
  123. }


  124. __DATA__
  125. A or B
  126. A or B or C
  127. (A or B)
  128. ((A or B) or C)
  129. (A or (B or C))
  130. (A not inside B)
  131. (A interact  ((B  or  C)  or (((D inside E) or F)  inside G)))
  132. (A interact  ((B  or  C)  or (((D inside E) or F)   not   inside G)))
复制代码

论坛徽章:
2
射手座
日期:2014-10-10 15:59:4715-16赛季CBA联赛之上海
日期:2016-03-03 10:27:14
40 [报告]
发表于 2013-12-24 21:30 |只看该作者
回复 38# MMMIX

牛啊!非常棒的语法解析~
   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP