2016-06-13 177 views
2

我想处理dypgen中的一些歧义。我在手册中发现了一些内容,我想知道,我该如何使用它。 在手动点5.2“上的符号模式匹配”有一个例如:dypgen中的模式匹配

expr: 
| expr OP<"+"> expr { $1 + $2 } 
| expr OP<"*"> expr { $1 * $2 } 

OP与“+”或匹配的“*”,我的理解。我也在那里找到:

这些模式可以是任何Caml模式(但没有关键字时)。 例如这是可能的:

expr: expr<(Function([arg1;arg2],f_body)) as f> expr 
{ some action } 

于是,我就放在那里一些其他的表情,但我不明白,发生了什么。如果我放在那里printf它输出匹配的字符串的值。但是,如果我在那里放入(fun x -> printf x),那在我看来就像printf一样,dypgen会抱怨语法错误并指向表达式的结尾。如果我把Printf.printf放在那里,它会抱怨Syntax error: operator expected。如果我把它放在那里(fun x -> Printf.printf x)它说:Lexing failed with message: lexing: empty token 这些不同的错误消息是什么意思?

最后,我想查找一个哈希表中的东西,如果值在那里,但我不知道,如果这是可能的话。它是不是可能?


编辑:派生自森林示例从dypgen演示的最小示例。

的grammarfile forest_parser.dyp包含:

{ 
open Parse_tree 
let dyp_merge = Dyp.keep_all 
} 

%start main 
%layout [' ' '\t'] 

%% 

main : np "." "\n" { $1 } 

np: 
    | sg     {Noun($1)} 
    | pl     {Noun($1)} 

sg: word <Word("sheep"|"fish")> {Sg($1)} 
sg: word <Word("cat"|"dog")> {Sg($1)} 
pl: word <Word("sheep"|"fish")> {Pl($1)} 
pl: word <Word("cats"|"dogs")> {Pl($1)} 

/* OR try: 
    sg: word <printf> {Sg($1)} 
    pl: word <printf> {Pl($1)} 
*/ 

word: 
    | (['A'-'Z' 'a'-'z']+) {Word($1)} 

的forest.ml现已以下print_forest功能:

let print_forest forest = 
    let rec aux1 t = match t with 
    | Word x 
    -> print_string x 
    | Noun (x) -> (
     print_string "N ["; 
     aux1 x; 
     print_string " ]") 
    | Sg (x) -> (
     print_string "Sg ["; 
     aux1 x; 
     print_string " ]") 
    | Pl (x) -> (
     print_string "Pl ["; 
     aux1 x; 
     print_string " ]") 
    in 
    let aux2 t = aux1 t; print_newline() in 
    List.iter aux2 forest; 
    print_newline() 

而且parser_tree.mli包含:

type tree = 
    | Word  of string 
    | Noun  of tree 
    | Sg   of tree 
    | Pl   of tree 

然后你可以确定,什么数字鱼,羊,猫等。

sheep or fish can be singular and plural. cats and dogs cannot. 

fish. 
N [Sg [fish ] ] 
N [Pl [fish ] ] 
+0

你如何解析你的函数? – Lhooq

+0

我用dypgen的演示为出发点,并使用这些makefile文件...语法是在.dyp-文件和它的作用: .dyp.ml: \t path_to_dypgen $ < \t ocamlc path_to_dyplib -C $ *。mli 我想现在,我被该构造函数的那个​​例子的模式语法困惑了。其他具有类型构造函数的ocaml模式可以工作。 (当然,printf不是一个模式,也许是它构建到dypgen中)但是我从来没有在手册中看到过类似的构造函数。 – gwf

+0

你可以添加一个你做过的最简单的例子吗? – Lhooq

回答

1

我对Dypgen一无所知,所以我试图弄明白。

让我们看看我发现了什么。

parser.dyp文件中,您可以定义词法分析器和分析器,也可以使用外部词法分析器。下面是我所做的:

我AST看起来是这样的:

parse_prog.mli

type f = 
    | Print of string 
    | Function of string list * string * string 

type program = f list 

prog_parser.dyp

{ 
    open Parse_prog 

    (* let dyp_merge = Dyp.keep_all *)  

    let string_buf = Buffer.create 10 
} 

%start main 

%relation pf<pr 

%lexer 

let newline = '\n' 
let space = [' ' '\t' '\r'] 
let uident = ['A'-'Z']['a'-'z' 'A'-'Z' '0'-'9' '_']* 
let lident = ['a'-'z']['a'-'z' 'A'-'Z' '0'-'9' '_']* 

rule string = parse 
    | '"' {() } 
    | _ { Buffer.add_string string_buf (Dyp.lexeme lexbuf); 
     string lexbuf } 

main lexer = 
    newline | space + -> {() } 
    "fun" -> ANONYMFUNCTION {() } 
    lident -> FUNCTION { Dyp.lexeme lexbuf } 
    uident -> MODULE { Dyp.lexeme lexbuf } 
    '"' -> STRING { Buffer.clear string_buf; 
        string lexbuf; 
        Buffer.contents string_buf } 

%parser 

main : function_calls eof           
    { $1 } 

function_calls: 
    |                 
    { [] } 
    | function_call ";" function_calls        
    { $1 :: $3 } 

function_call: 
    | printf STRING             
    { Print $2 } pr 
    | "(" ANONYMFUNCTION lident "->" printf lident ")" STRING   
    { Print $6 } pf 
    | nested_modules "." FUNCTION STRING        
    { Function ($1, $3, $4) } pf 
    | FUNCTION STRING             
    { Function ([], $1, $2) } pf 
    | "(" ANONYMFUNCTION lident "->" FUNCTION lident ")" STRING  
    { Function ([], $5, $8) } pf 

printf: 
    | FUNCTION<"printf">            
    {() } 
    | MODULE<"Printf"> "." FUNCTION<"printf">       
    {() } 

nested_modules: 
    | MODULE          
    { [$1] } 
    | MODULE "." nested_modules      
    { $1 :: $3 } 

此文件是最重要的。正如你所看到的,如果我有一个函数printf "Test",我的语法是不明确的,这可以被简化为Print "Test"Function ([], "printf", "Test"),但是,正如我意识到的那样,我可以给予我的规则优先级,所以如果一个作为更高优先级,它将是一个选择用于第一个解析。 (试着取消let dyp_merge = Dyp.keep_all的评论,你会看到所有可能的组合)。

在我的主:

main.ml

open Parse_prog 

let print_stlist fmt sl = 
    match sl with 
    | [] ->() 
    | _ -> List.iter (Format.fprintf fmt "%s.") sl 

let print_program tl = 
    let aux1 t = match t with 
     | Function (ml, f, p) -> 
     Format.printf "I can't do anything with %a%s(\"%s\")@." print_stlist ml f p 
     | Print s -> Format.printf "You want to print : %[email protected]" s 
    in 
    let aux2 t = List.iter (fun (tl, _) -> 
    List.iter aux1 tl; Format.eprintf "[email protected]") tl in 
    List.iter aux2 tl 

let input_file = Sys.argv.(1) 

let lexbuf = Dyp.from_channel (Forest_parser.pp()) (Pervasives.open_in input_file) 

let result = Parser_prog.main lexbuf 

let() = print_program result 

而且,例如,以下文件:

测试

printf "first print"; 
Printf.printf "nested print"; 
Format.eprintf "nothing possible"; 
(fun x -> printf x) "Anonymous print"; 

如果我前ecute ./myexec test我会得到如下提示

You want to print : first print 
You want to print : nested print 
I can't do anything with Format.eprintf("nothing possible") 
You want to print : x 
------------ 

所以,TL; DR,手动的例子是就在这里告诉你,你可以用你的义令牌玩(我从来没有定义的标记打印,只是功能)并匹配它们以获得新的规则。

我希望这是明确的,我学到了很多与你的问题;-)

[编辑]于是,我改变了解析器来匹配你想要观看的内容:

{ 
     open Parse_prog 

     (* let dyp_merge = Dyp.keep_all *) 

     let string_buf = Buffer.create 10 
    } 

    %start main 

    %relation pf<pp 

    %lexer 

    let newline = '\n' 
    let space = [' ' '\t' '\r'] 
    let uident = ['A'-'Z']['a'-'z' 'A'-'Z' '0'-'9' '_']* 
    let lident = ['a'-'z']['a'-'z' 'A'-'Z' '0'-'9' '_']* 

    rule string = parse 
     | '"' {() } 
     | _ { Buffer.add_string string_buf (Dyp.lexeme lexbuf); 
      string lexbuf } 

    main lexer = 
     newline | space + -> {() } 
     "fun" -> ANONYMFUNCTION {() } 
     lident -> FUNCTION { Dyp.lexeme lexbuf } 
     uident -> MODULE { Dyp.lexeme lexbuf } 
     '"' -> STRING { Buffer.clear string_buf; 
         string lexbuf; 
         Buffer.contents string_buf } 

    %parser 

    main : function_calls eof           
     { $1 } 

    function_calls: 
     |                 
     { [] } pf 
     | function_call <Function((["Printf"] | []), "printf", st)> ";" function_calls 
     { (Print st) :: $3 } pp 
     | function_call ";" function_calls        
     { $1 :: $3 } pf 


    function_call: 
     | nested_modules "." FUNCTION STRING       
     { Function ($1, $3, $4) } 
     | FUNCTION STRING        
     { Function ([], $1, $2) } 
     | "(" ANONYMFUNCTION lident "->" FUNCTION lident ")" STRING 
     { Function ([], $5, $8) } 

    nested_modules: 
     | MODULE          
     { [$1] } 
     | MODULE "." nested_modules      
     { $1 :: $3 } 

这里,正如你所看到的,我并没有处理这样一个事实,即当我解析它时,我的函数是打印的,但是当我把它放到我的函数列表中。所以,我匹配我的解析器构建的algebraic type。我希望这个例子对你是好的;-)(但要注意,这是非常含糊的!:-D)

+0

您忘记在那里更改Forest_Parser的名称,但它可以与Prog_Parser一起使用。你产生了一个非常ambigous语法:) 另一件事是,我没有找到,我在找什么。我看到这些标签为“<…>”的解析器printf-rule,并且在那里放置了一个字符串模式 - 我可以理解。但是我想知道,我如何将<(Function([arg1; arg2],f_body))这样的表达式作为f>放在手册的例子中。 (你可以像下面的“match ... with”一样放入每个模式(http://caml.inria.fr/pub/docs/manual-ocaml/patterns.html),并且感谢你的例子。 – gwf

+0

I'll更新我的例子,然后;-) – Lhooq