2016-06-13 2 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의 forest-example에서 파생 된 최소 예입니다. forest.ml 이제 다음 print_forest 기능이

{ 
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)} 

:

grammarfile forest_parser.dyp는 포함

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 

그리고 당신은 numeri 물고기, 양, 고양이 (들) 등이 무엇인지를 결정할 수 있습니다.

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"; 

하는 경우 전예요. DR가 수동 예를 들어 당신이 정의 된 토큰 재생할 수 있음을 보여주기 위해 여기 있었다 (I 토큰 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을 얻을 것이다) 그리고 새로운 규칙을 얻기 위해 그들과 일치하십시오. 나는 그것이 분명 희망

, 나는 귀하의 질문에 ;-)로 많은 것을 배웠

그래서, 난 당신이보고 싶어 일치하는 파서 변경 [편집] : 여기

{ 
     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