解析 – 为不同arity的规则指定常见的语法操作

前端之家收集整理的这篇文章主要介绍了解析 – 为不同arity的规则指定常见的语法操作前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试为一个简单的DSL编写一个解析器,它在表单< statementName>中有十几个语句. <参数1> < param2的> ……;,参数数量变化的地方.由于语句的结构非常相似(所有匹配的语句名称字符串后跟一系列由名称给出的标记),并且结果的结构非常相似(所有存储语句名称和参数的哈希值),我想知道如何指定想要的结果结构,而不必为每个语句操作重复自己.

动作类的伪代码,可以帮助我指定这样的结果结构:

class FooActions {

  method *_stmt ($/) { 
    @result[0] = make string of statement name $/[0];
    @result[1] = make hash of $/[1..] with the keys being the name of the rule 
      at index (i.e. '"var"' for `<var=identifier>` and `"type"` for `<type>`,etc.) and 
      values being the `.made` results for the rules at index (see below);
    return @result;
  }

  method identifier ($/) { return ~$/ }

  method number ($/) { return +$/ }

  method type ($/) { return ~$/ }
}

测试文件

use v6;
use Test;
use Foo;
my $s;
$s = 'GoTo 2 ;';
is_deeply Foo::FooGrammar.parse($s).made,('GoTo',{pos => 2});
$s = 'Set foo 3 ;';
is_deeply Foo::FooGrammar.parse($s).made,('Set',{var => 'foo',target => 3});
$s = 'Get bar Long ;';
is_deeply Foo::FooGrammar.parse($s).made,('Get',{var => 'bar',type => 'Long'});
$s = 'Set foo bar ;';
is_deeply Foo::FooGrammar.parse($s).made,target => 'bar'});

语法:

use v6;
unit package Foo;

grammar FooGrammar is export {
  rule TOP { <stmt> ';' }
  rule type { 'Long' | 'Int' }
  rule number { \d+ }
  rule identifier { <alpha> \w* }
  rule numberOrIdentifier { <number> || <identifier> }

  rule goto_stmt { 'GoTo' <pos=number> }
  rule set_stmt { 'Set' <var=identifier> <target=numberOrIdentifier> }
  rule get_stmt { 'Get' <var=identifier> <type> }
  rule stmt { <goto_stmt> || <set_stmt> || <get_stmt> }
}

解决方法

方法将每个语句类型表示为 Proto-regex,并使用 syms来避免重复语句关键字(GoTo等).

个别陈述没有行动方法.这些是在下一级(TOP)处理的,它在匹配时使用caps方法将其转换为哈希.

< sym> capture用于额外关键字.行的其余部分转换为哈希.解决方法如下

语法和行动:

use v6;
unit package Foo;

grammar Grammar is export {
  rule TOP { <stmt> ';' }
  token type { 'Long' | 'Int' }
  token number { \d+ }
  token identifier { <alpha>\w* }
  rule numberOrIdentifier { <number> || <identifier> }

  proto rule stmt {*}
  rule stmt:sym<GoTo> { <sym> <pos=.number> }
  rule stmt:sym<Set>  { <sym> <var=.identifier> <target=.numberOrIdentifier> }
  rule stmt:sym<Get>  { <sym> <var=.identifier> <type> }
}

class Actions {
      method number($/)     { make +$/ }
      method identifier($/) { make ~$/ }
      method type($/)       { make ~$/ }
      method numberOrIdentifier($/)   { make ($<number> // $<identifier>).made }
      method TOP($/) {
          my %caps = $<stmt>.caps;
          my $keyw = .Str
              given %caps<sym>:delete;
          my %args = %caps.pairs.map: {.key => .value.made};
          make ($keyw,%args,);
      }
   }

测试:

use v6;
use Test;
use Foo;
my $actions = Foo::Actions.new;
my $s;
$s = 'GoTo 2 ;';
is-deeply Foo::Grammar.parse($s,:$actions).made,{pos => 2});
$s = 'Set foo 3;';
is-deeply Foo::Grammar.parse($s,target => 3});
$s = 'Get bar Long ;';
is-deeply Foo::Grammar.parse($s,type => 'Long'});
$s = 'Set foo bar ;';
is-deeply Foo::Grammar.parse($s,target => 'bar'});

猜你在找的Perl相关文章