2015-12-14 12 views
6

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

मेरे सभी छोटे टोकन पार्सर्स ठीक से काम कर रहे प्रतीत होते हैं; इस समय यह मेरा कोड का एक टुकड़ा है:

:- use_module(library(dcg/basics)). 

operator('(') --> "(".  operator(')') --> ")". 
operator('[') --> "[".  operator(']') --> "]". 
% ... etc. 

keyword(array) --> "array". 
keyword(break) --> "break". 
% ... etc. 

यह एक सा दोहराव है, लेकिन यह काम करने लगता है। तब मैं कुछ सामान मैं पूरी तरह से प्यार नहीं करते और पर सुझावों का स्वागत होता है, लेकिन काम करने के लिए प्रतीत होता है:

मेरी tokenizer के लिए मुख्य शासन यह है:

token(X) --> whites, (keyword(X) ; operator(X) ; id(X) ; int(X) ; string(X)). 

यह सही नहीं है, मुझे intin,id(t) में पार्स किया जाएगा क्योंकि keyword(X)id(X) से पहले आता है। तो मुझे लगता है कि यह पहला सवाल है।

मेरे पास बड़ा सवाल यह है कि मैं नहीं देखता कि इस स्थिति में टिप्पणियों को सही तरीके से कैसे एकीकृत किया जाए। मैंने निम्नलिखित कोशिश की है:

skipAhead --> []. 
skipAhead --> (comment ; whites), skipAhead. 

comment --> "/*", anything, "*/". 
anything --> []. 
anything --> [_], anything. 

token(X) --> skipAhead, (keyword(X) ; operator(X) ; id(X) ; int(X) ; string(X)). 

यह काम नहीं प्रतीत होता है; पार्स जो लौटते हैं (और मुझे कई पार्स मिलते हैं) ऐसा लगता है कि टिप्पणी को हटा दिया गया है। मैं घबरा गया हूं कि मेरा टिप्पणी नियम अनावश्यक रूप से अक्षम है और शायद बहुत अनावश्यक बैकट्रैकिंग को प्रेरित करता है। मैं भी घबरा गया हूं कि whites//0 डीसीजी/मूलभूत से निर्धारक है; हालांकि, समीकरण का वह हिस्सा काम करता प्रतीत होता है, यह सिर्फ टिप्पणी छोड़ने के साथ इसे एकीकृत कर रहा है जो ऐसा प्रतीत नहीं होता है।

अंतिम नोट के रूप में, मुझे नहीं लगता कि यहां से लाइन/कॉलम जानकारी वाले उपयोगकर्ता को प्रचारित पार्स त्रुटियों को कैसे संभालना है। ऐसा लगता है कि मुझे किसी प्रकार की वर्तमान लाइन/कॉलम जानकारी के माध्यम से ट्रैक करना और थ्रेड करना होगा और इसे टोकन में लिखना होगा और फिर शायद लाइन को पुनर्निर्माण करने का प्रयास करें यदि मैं कुछ ऐसा करना चाहता हूं जो इसे कैसे करता है। क्या यह निष्पक्ष है या वहां "अनुशंसित अभ्यास" है?

पूरा कोड in this haste पाया जा सकता है।

+0

घबराहट wrt के लिए अच्छा कारण। 'टिप्पणी // 0':' वाक्यांश (टिप्पणी, "/ **/* /") सत्य है, लेकिन असफल होना चाहिए। – false

उत्तर

2

मेरे पास त्रुटि रिपोर्टिंग का समर्थन करने के लिए यह कोड है, जिसे स्वयं को सावधानीपूर्वक संभाला जाना चाहिए, सार्थक संदेशों को छिड़कना और कोड के चारों ओर 'नियम छोड़ना'। लेकिन उपयोग में आसान विकल्प नहीं है: एक डीसीजी एक अच्छा गणना इंजन है, लेकिन यह विशेष पार्सिंग इंजन के साथ-साथ-बॉक्स में प्रतिस्पर्धा नहीं कर सकता है, जो स्वचालित रूप से त्रुटि संदेशों को उत्सर्जित करने में सक्षम हैं, सैद्धांतिक गुणों का शोषण कर रहा है लक्षित व्याकरण ...

:- dynamic text_length/1. 

parse_conf_cs(Cs, AST) :- 
    length(Cs, TL), 
    retractall(text_length(_)), 
    assert(text_length(TL)), 
    phrase(cfg(AST), Cs). 
.... 
%% tag(?T, -X, -Y)// is det. 
% 
% Start/Stop tokens for XML like entries. 
% Maybe this should restrict somewhat the allowed text. 
% 
tag(T, X, Y) --> 
    pos(X), unquoted(T), pos(Y). 
.... 

%% pos(-C, +P, -P) is det. 
% 
% capture offset from end of stream 
% 
pos(C, P, P) :- text_length(L), length(P, Q), C is L - Q. 

टैग // 3 सिर्फ एक उदाहरण के उपयोग, इस पार्सर मैं एक संपादन योग्य एएसटी निर्माण कर रहा हूँ में है, इसलिए मैं पदों की दुकान ठीक से एक संपादक में प्रत्येक नेस्टेड हिस्सा संबद्ध कर पाने के लिए ...

संपादित

आईडी के लिए एक छोटे से वृद्धि // 1: SWI-Prolog उस के लिए code_type/2 विशेष:

1 ?- code_type(0'a, csymf). 
true. 

2 ?- code_type(0'1, csymf). 
false. 

तो

id([C|Cs]) --> [C], {code_type(C, csymf)}, id_rest(Cs). 

id_rest([C|Cs]) --> [C], {code_type(C, csym)}, id_rest(Cs). 
id_rest([]) --> []. 

(अधिक शाब्दिक परिवर्तन glossing) अपने रवैया छोटे स्निपेट सामान्यीकरण करने के लिए पर निर्भर करता है, और वास्तविक व्याकरण विवरण, id_rest // 1 हो सकता है पुन: प्रयोज्य फैशन में लिखा है, और नियतात्मक

id([C|Cs]) --> [C], {code_type(C, csymf)}, codes(csym, Cs). 

% greedy and deterministic 
codes(Kind, [C|Cs]) --> [C], {code_type(C, Kind)}, !, codes(Kind, Cs). 
codes(Kind, []), [C] --> [C], {\+code_type(C, Kind)}, !. 
codes(_, []) --> []. 

आईडी के इस सख्त परिभाषा // 1 भी कीवर्ड के साथ कुछ अस्पष्टता wrt पहचानकर्ता को दूर करने की अनुमति होगी जनसंपर्क बनाया efix: recoding कीवर्ड // 1

तरह
keyword(K) --> id(id(K)), {memberchk(K, [ 
    array, 
    break, 
... 
]}. 

सही ढंग से पहचान करेगा

?- phrase(tokenize(Ts), `if1*2`). 
Ts = [id(if1), *, int(2)] ; 

आपका स्ट्रिंग // 1 (ओटी: पुस्तकालय के साथ क्या दुर्भाग्यपूर्ण संघर्ष (DCG/मूल बातें): स्ट्रिंग // 1) है एक सरल 'त्रुटि वसूली रणनीति' को लागू करने के लिए एक आसान उम्मीदवार:

stringChar(0'\") --> "\\\\". 
stringChar(0'") --> pos(X), "\n", {format('unclosed string at ~d~n', [X])}. 

यह का एक उदाहरण 'रिपोर्ट त्रुटि और डालने टोकन गुम' है, तो पार्स कर सकते हैं जाओ ...

5

यह वर्तमान में अभी भी थोड़ा अजीब (unreadableNamesLikeInJavaAnyone?) है, लेकिन इसके मूल में यह काफी ठोस है, इसलिए मैं केवल कोड के कुछ पहलुओं और सवालों के बारे में कुछ टिप्पणी है:

  1. अलग से lexing पार्सिंग सही समझ में आता है। यह प्रक्रिया के लिए पार्सर के लिए फॉर्म l_c_t(Line,Column,Token) या Token-lc(Line,Column) के टोकन (उदाहरण के लिए) छोड़कर प्रत्येक टोकन के साथ लाइन और कॉलम जानकारी को स्टोर करने का एक पूरी तरह स्वीकार्य समाधान भी है।
  2. टिप्पणियां हमेशा खराब होती हैं, या मुझे कहना चाहिए, अक्सर नॉनस्टी? डीसीजी में एक उपयोगी पैटर्न अक्सर सबसे लंबे मैच के लिए जाना जाता है, जिसे आप पहले से ही कुछ मामलों में उपयोग कर रहे हैं, लेकिन अभी तक anything//0 के लिए नहीं। तो, दो नियमों को पुन: व्यवस्थित करने से आप टिप्पणी करने के लिए हर चीज को छोड़ने में मदद कर सकते हैं।
  3. निर्धारणा के संबंध में: मिलान करने वाले पहले पार्स को प्रतिबद्ध करना ठीक है, लेकिन इसे केवल एक बार करें, और घोषणात्मक व्याकरण को गड़बड़ाने के प्रलोभन का विरोध करें।
  4. डीसीजी में, ; के बजाय | का उपयोग करना सुरुचिपूर्ण है।
  5. tokenize//1? आ जाओ! यह सिर्फ tokens//1 है। यह सभी दिशाओं में समझ में आता है।
+2

मैं इस बात के बारे में एक निर्णायक निर्णय लेने में कभी सक्षम नहीं हूं कि क्या कैमलकेस ठीक है या प्रोलॉग में नहीं है ... अगर उन्हें व्यापक रूप से गैर-लोकप्रिय माना जाता है तो मैं अंडरस्कोर पर वापस आऊंगा। मुझे वास्तव में टोकन-लोक (रेखा, कर्नल) का विचार पसंद है, हालांकि, जब तक आवश्यक हो तब अनदेखा करना आसान नहीं है। –

+2

'itIsEasyToSeeThatIdentifiersInCamelCaseCannotBeEasilyRead', जबकि' names_with_underscores_are_perfectly_readable_even_for_longer_names' का उपयोग करते हुए। – mat

+2

मेरे पास जावा अनुभव के बहुत से वर्षों का अनुभव है कि यह "देखने में आसान" है। हम रोज़ाना उपयोग करते हुए प्रशिक्षित होते हैं। –

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