2016-06-13 136 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