2012-03-27 17 views
11

ओकैम की बात आती है जब मैं पूरी नौसिखिया हूं। मैंने हाल ही में भाषा का उपयोग शुरू कर दिया है (लगभग 2 सप्ताह पहले), लेकिन दुर्भाग्य से, मुझे एक सिंटैक्स विश्लेषक (पार्सर + लेक्सर, जिसका फ़ंक्शन या तो स्वीकार करने या वाक्य नहीं है) बनाने के लिए काम किया गया है मेनिर का उपयोग करना अब, मुझे ओकैमल और मेनिर के बारे में इंटरनेट पर कुछ सामग्री मिली है:ओकैमल + मेनिर संकलन/लेखन

मेनिर मैनुअल।

This webpage for some French University course.

Sourceforge पर टॉस के मुखपृष्ठ पर एक छोटी Menhir ट्यूटोरियल।

डेरडन द्वारा जिथब पर एक मेनिर उदाहरण।

A book on OCaml (with a few things about ocamllex+ocamlyacc

SooHyoung ओह द्वारा एक यादृच्छिक ocamllex ट्यूटोरियल।

और मेनिर के स्रोत कोड के साथ आने वाले उदाहरण।

(मैं दो से अधिक हाइपरलिंक नहीं डाल सकते, इसलिए मैं आपको वेबसाइटों मैं यहाँ यह उल्लेख कर रहा हूँ में से कुछ से सीधे लिंक नहीं कर सकते। क्षमा करें!)

तो, जैसा कि आप देख सकते हैं, मैं मैं इस कार्यक्रम के निर्माण में सहायता करने के लिए अधिक से अधिक सामग्री की तलाश कर रहा हूं। दुर्भाग्य से, मैं अभी भी कई अवधारणाओं को समझ नहीं सकता, और इस तरह, मुझे कई, कई कठिनाइयों का सामना करना पड़ रहा है।

स्टार्टर्स के लिए, मुझे नहीं पता कि मेरे प्रोग्राम को सही तरीके से कैसे संकलित किया जाए। मैं निम्नलिखित कमांड का उपयोग कर रहा हूं:

ocamlbuild -use-menhir -menhir "menhir --external-tokens Tokens" main.native 

मेरा प्रोग्राम चार अलग-अलग फ़ाइलों में विभाजित है: main.ml; lexer.mll; parser.mly; tokens.mly। main.ml वह हिस्सा है जो तर्क के रूप में दिए गए फ़ाइल सिस्टम में फ़ाइल से इनपुट प्राप्त करता है।

let filename = Sys.argv.(1) 

let() = 
    let inBuffer = open_in filename in 
    let lineBuffer = Lexing.from_channel inBuffer in 
    try 
     let acceptance = Parser.main Lexer.main lineBuffer in 
     match acceptance with 
      | true -> print_string "Accepted!\n" 
      | false -> print_string "Not accepted!\n" 
    with 
     | Lexer.Error msg -> Printf.fprintf stderr "%s%!\n" msg 
     | Parser.Error -> Printf.fprintf stderr "At offset %d: syntax error.\n%!" (Lexing.lexeme_start lineBuffer) 

दूसरी फ़ाइल lexer.mll है।

{ 
    open Tokens 
    exception Error of string 
} 

rule main = parse 
    | [' ' '\t']+ 
     { main lexbuf } 
    | ['0'-'9']+ as integer 
     { INT (int_of_string integer) } 
    | "True" 
     { BOOL true } 
    | "False" 
     { BOOL false } 
    | '+' 
     { PLUS } 
    | '-' 
     { MINUS } 
    | '*' 
     { TIMES } 
    | '/' 
     { DIVIDE } 
    | "def" 
     { DEF } 
    | "int" 
     { INTTYPE } 
    | ['A'-'Z' 'a'-'z' '_']['0'-'9' 'A'-'Z' 'a'-'z' '_']* as s 
     { ID (s) } 
    | '(' 
     { LPAREN } 
    | ')' 
     { RPAREN } 
    | '>' 
     { LARGER } 
    | '<' 
     { SMALLER } 
    | ">=" 
     { EQLARGER } 
    | "<=" 
     { EQSMALLER } 
    | "=" 
     { EQUAL } 
    | "!=" 
     { NOTEQUAL } 
    | '~' 
     { NOT } 
    | "&&" 
     { AND } 
    | "||" 
     { OR } 
    | '(' 
     { LPAREN } 
    | ')' 
     { RPAREN } 
    | "writeint" 
     { WRITEINT } 
    | '\n' 
     { EOL } 
    | eof 
     { EOF } 
    | _ 
     { raise (Error (Printf.sprintf "At offset %d: unexpected character.\n" (Lexing.lexeme_start lexbuf))) } 

तीसरी फ़ाइल पार्सर.मी है।

%start <bool> main 
%% 

main: 
| WRITEINT INT { true } 

चौथे tokens.mly

%token <string> ID 
%token <int> INT 
%token <bool> BOOL 
%token EOF EOL DEF INTTYPE LPAREN RPAREN WRITEINT 
%token PLUS MINUS TIMES DIVIDE 
%token LARGER SMALLER EQLARGER EQSMALLER EQUAL NOTEQUAL 
%token NOT AND OR 

%left OR 
%left AND 
%nonassoc NOT 
%nonassoc LARGER SMALLER EQLARGER EQSMALLER EQUAL NOTEQUAL 
%left PLUS MINUS 
%left TIMES DIVIDE 
%nonassoc LPAREN 
%nonassoc ATTRIB 

%{ 
type token = 
    | ID of (string) 
    | INT 
    | BOOL 
    | DEF 
    | INTTYPE 
    | LPAREN 
    | RPAREN 
    | WRITEINT 
    | PLUS 
    | MINUS 
    | TIMES 
    | DIVIDE 
    | LARGER 
    | SMALLER 
    | EQLARGER 
    | EQSMALLER 
    | EQUAL 
    | NOTEQUAL 
    | NOT 
    | AND 
    | OR 
    | EOF 
    | EOL 
%} 

%% 

अब है, मुझे पता है कि यहां अप्रयुक्त प्रतीकों में से एक बहुत कुछ है, लेकिन मैं उन्हें अपने पार्सर में उपयोग करना चाहते हैं। कोई फर्क नहीं पड़ता कि मैं फ़ाइलों में कितने बदलाव करता हूं, संकलक मेरे चेहरे पर उड़ता रहता है। मैंने जो कुछ भी सोच सकता हूं उसकी कोशिश की है, और कुछ भी काम नहीं करता है। यह क्या है कि अनबाउंड कन्स्ट्रक्टर और गैर-परिभाषित प्रारंभ प्रतीकों की त्रुटियों में ओकम्बुबिल्ड विस्फोट कर रहा है? प्रोग्राम को ठीक से संकलित करने के लिए मुझे किस कमांड का उपयोग करना चाहिए? मेनिर के बारे में जानने के लिए मुझे सार्थक सामग्री कहां मिल सकती है?फिर, मैं जादू विकल्प नहीं जानते ocamlbuild को पारित करने के लिए

%token <string> ID 
%token <int> INT 
%token <bool> BOOL 
%token EOF EOL DEF INTTYPE LPAREN RPAREN WRITEINT 
%token PLUS MINUS TIMES DIVIDE 
%token LARGER SMALLER EQLARGER EQSMALLER EQUAL NOTEQUAL 
%token NOT AND OR 

%left OR 
%left AND 
%nonassoc NOT 
%nonassoc LARGER SMALLER EQLARGER EQSMALLER EQUAL NOTEQUAL 
%left PLUS MINUS 
%left TIMES DIVIDE 
%nonassoc LPAREN 
%nonassoc ATTRIB 

%% 

और मैं बहुत अच्छी तरह से menhir पता नहीं है,:

उत्तर

8

ऐसा करने का एक आसान तरीका Parser/Tokens अलगाव को निकालना है। जैसा कि थॉमस ने नोट किया था, type token = ... की घोषणा की कोई आवश्यकता नहीं है, क्योंकि यह स्वचालित रूप से %token निर्देशों से मेनिर द्वारा उत्पादित किया जाता है।

तो तुम परिभाषित कर सकते हैं parser.mly के रूप में:

%start <bool> main 

%token <string> ID 
%token <int> INT 
%token <bool> BOOL 
%token EOF EOL DEF INTTYPE LPAREN RPAREN WRITEINT 
%token PLUS MINUS TIMES DIVIDE 
%token LARGER SMALLER EQLARGER EQSMALLER EQUAL NOTEQUAL 
%token NOT AND OR 

%left OR 
%left AND 
%nonassoc NOT 
%nonassoc LARGER SMALLER EQLARGER EQSMALLER EQUAL NOTEQUAL 
%left PLUS MINUS 
%left TIMES DIVIDE 
%nonassoc LPAREN 
%nonassoc ATTRIB 
%% 

main: 
| WRITEINT INT { true } 

और lexer.mll के रूप में:

{ 
    open Parser 
    exception Error of string 
} 

[...] (* rest of the code not shown here *) 

तो tokens.mly हटाने, और

ocamlbuild -use-menhir main.native 

साथ संकलन और यह सब अच्छी तरह से काम करता है।

+0

दरअसल, केवल एक 'mly' होने से बहुत आसान है। मैंने अपने जवाब में उस समाधान का प्रस्ताव नहीं दिया है क्योंकि मैं मान रहा था कि @ लोप्सन मेनिर की "पार्सिंग इकाइयों के अलग संकलन" का उपयोग करना चाहता था। – Thomas

+0

सभी मदद के लिए धन्यवाद, दोस्तों, आपको नहीं पता कि आपकी पोस्ट कितनी मूल्यवान थी! अंत में, चीजें कुछ समझने शुरू कर रही हैं। –

7

तो सबसे पहले, आप tokens.mly में टोकन repet की जरूरत नहीं

menhir tokens.mly parser.mly -base parser 

, यदि आप lexer.mll में Parser byt Token के किसी भी घटना की जगह फिर, 012: लेकिन, मेरी समझ में आप के लिए "पैक" सभी .mly एक पार्सर में इकाई की जरूरत हैकाम करना चाहिए। ध्यान दें कि हालांकि ऐसा करने का एक चालाक तरीका हो सकता है।

1

मैं एक ही समस्या में भाग गया, इसके अलावा पार्सर को वर्तमान प्रत्यक्ष के बाहर मॉड्यूल की आवश्यकता थी। । मैं समझ नहीं सकता था कि पार्सर निर्दिष्ट करने के लिए ocamlbuild आह्वान करने के लिए कैसे {मिलीलीटर, MLI} 3 MLY फाइलों से बनाया जा सकता था, इसलिए मैं बस एक makefile कि बनाया:

  • प्रतियां मॉड्यूल _build से .cmi वर्तमान निर्देशिका में (पूरा करने के menhir --infer)
  • menhir आह्वान
  • की नकल की मॉड्यूल निकाल
  • ocamlbuild को पूरा करने के तो ocamlbuild आह्वान

मैं इसे से संतुष्ट नहीं हूं, इसलिए मैं दिलचस्पी किसी भी बेहतर alt में ernative, लेकिन अगर आपको वास्तव में कम से कम प्रयास के साथ अपना प्रोजेक्ट पूरा करना है, तो मुझे लगता है कि

संपादित करें: असल में, संकलित मॉड्यूल की प्रतिलिपि बनाने और निकालने की कोई आवश्यकता नहीं है, बस मेनिर के विकल्प को पास करें दूसरे चरण के लिए: menhir --ocamlc "ocamlc मैं \" ../_ निर्माण/मॉड्यूल/\ "" --infer --base पार्सर

दुख की बात है, इस चित्र का मतलब है कि पार्सर पीढ़ी पिछले wRT हो जाएगा मॉड्यूल का संकलन, इसलिए एक अनावश्यक (और असफल) पहले संकलन की उम्मीद की जानी चाहिए।

संबंधित मुद्दे