2016-06-13 8 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 Что означают эти разные сообщения об ошибках?

В конце концов, я хотел бы найти что-то в хэш-таблице, если значение там, но я не знаю, если это возможно. Это или не возможно?


EDIT: минимальный пример, полученный из примера леса из dypgen-demos.

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 вы можете определить лексер и синтаксический анализатор, или вы можете использовать внешний лексер. Вот что я сделал:

Мой аст выглядит следующим образом:

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, руководство примера только что был здесь, чтобы показать вам, что вы можете играть с определенными маркерами (я никогда не определен маркером PRINT, просто FUNCTION) и сопоставить их, чтобы получить новые правила.

Я надеюсь, что это ясно, я узнал много с вопросом ;-)

[EDIT] Итак, я изменил парсер, чтобы соответствовать, что вы хотели смотреть:

{ 
     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. Вы произвели очень амбициозную грамматику :) Другое дело, что я не нахожу, чего я искал. Я вижу синтаксический анализатор printf-rule с этими тегами «<…>», и вы вставляете туда шаблон строки, который я могу понять. Но я хотел знать, как я могу выразить некоторые выражения типа <(Function ([arg1; arg2], f_body)) как f>, как в примере в руководстве. (Вы можете поместить туда каждый шаблон, как «match ... with» (http://caml.inria.fr/pub/docs/manual-ocaml/patterns.html). И спасибо за пример. – gwf

+0

Я буду обновите мой пример, затем ;-) – Lhooq