2010-11-10 11 views
14

मैं अपने फ्लेक्स में पार्स करने के लिए सी-शैली बहु लाइन टिप्पणी कोशिश कर रहा हूँ (.l) फ़ाइल:फ्लेक्स/बाइसन में बहु-पंक्ति टिप्पणियां इतनी उत्पीड़न क्यों हैं?

%s ML_COMMENT 
%% 

... 

<INITIAL>"/*"     BEGIN(ML_COMMENT); 
<ML_COMMENT>"*/"    BEGIN(INITIAL); 
<ML_COMMENT>[.\n]+    { } 

मैं किसी भी टोकन और मेरी व्याकरण (.y) टिप्पणियों को संबोधित नहीं करता वापस नहीं कर रहा हूँ किसी भी प्रकार।

जब मैं अपने निष्पादन योग्य चलाने के लिए, मैं एक पार्स त्रुटि मिलती है:

$ ./a.out 
/* 
abc 
def 
Parse error: parse error 
$ echo "/* foo */" | ./a.out 
Parse error: parse error 

(मेरे yyerror समारोह एक printf (करता है "पार्स त्रुटि:% s \ n") है, जो जहां की पहली छमाही अनावश्यक त्रुटि संदेश से आता है)।

मैं देख सकता हूं कि दूसरा उदाहरण इनपुट की संपूर्णता क्यों विफल रहता है, और चूंकि व्याकरण द्वारा टिप्पणियों को अनदेखा किया जाता है, इसलिए कोई बयान नहीं है। इस प्रकार इनपुट एक वैध कार्यक्रम नहीं है। लेकिन इससे पहले कि मैं टिप्पणी खत्म करने से पहले पहला भाग एक पार्स त्रुटि फेंकता है।

भी भ्रामक:

$ ./a.out 
/* foo */ 
a = b; 
Parse error: parse error 

इस मामले में, टिप्पणी से पहले वास्तविक मान्य इनपुट (जो, टिप्पणी के बिना, ठीक से पार्स) के लिए बंद है। विफलता वास्तव में "ए" को पार्स करने के बाद होती है, असाइनमेंट "ए = बी;" को पार्स करने का प्रयास करने के बाद नहीं। अगर मैं अपनी लाइन पर "ए" दर्ज करता हूं, तो यह अभी भी एक त्रुटि फेंकता है।

यह देखते हुए कि त्रुटि संदेश एक पार्सर त्रुटि है और स्कैनर त्रुटि नहीं है, क्या मेरे पास मेरी फ़ाइल में कुछ महत्वपूर्ण है? या क्या मैं अपने स्कैनर नियमों में कुछ गलत कर रहा हूं जो पार्सर साइड पर फैलता है?

संपादित करें: प्रति रूडी के सुझाव @, मैं डिबगिंग के बारे में बदल गया और पाया:

$ ./a.out 
Starting parse 
Entering state 0 
Reading a token: /* 
foo 
Next token is 44 (IDENTIFER) 
Shifting token 44 (IDENTIFER), Entering state 4 
Reducing via rule 5 (line 130), IDENTIFER -> identifier 
state stack now 0 
Entering state 5 

मैं डिबगिंग बंद कर दिया और पाया कि /* foo */ = bar; वास्तव में foo = bar; रूप में एक ही पार्स करता है। मैं फ्लेक्स 2.5.4 का उपयोग कर रहा हूँ; यह मुझे उन राज्यों के नियमों के बारे में कोई चेतावनी नहीं देता है जिन्हें मैं उपयोग करने का प्रयास कर रहा हूं।

+1

मैं जीएनयू-फ्लेक्स के लिए फ्लेक्स retagged। आपके स्कैनर नियम ठीक दिखते हैं। पार्स त्रुटि पार्सर में अमान्य टोकन इनपुट इंगित करती है। आप कुछ संबंधित बाइसन नियम पोस्ट करना चाह सकते हैं। इसके अतिरिक्त, आपके बाइसन नियमों के अंदर printf() कथन डालना एक अच्छा विचार हो सकता है, इस प्रकार आप देख सकते हैं कि टोकन स्कैनिंग के दौरान पार्सर किस नियम का प्रयास कर रहा है। – Kizaru

+2

अपने स्कैनर के लिए एक अलग परीक्षण दोहन बनाना भी एक अच्छा विचार होगा। इस तरह आप पार्सर दोषों से स्कैनर दोषों को अलग कर सकते हैं। कोई भी स्कैनर-पार्सर सिस्टम इतना जटिल है कि आपको एकीकरण परीक्षण करके अतिरिक्त जटिलता को इंजेक्ट करने की आवश्यकता नहीं है जब आप वास्तव में चाहते हैं कि यूनिट परीक्षण करना ... – bstpierre

+1

जब आप अपने बाइसन में '--debug' ध्वज जोड़ते हैं 'yyparse()' कॉल से पहले 'yydebug = 1' सेट करें, फिर पार्सर लेक्सर से देखे गए प्रत्येक टोकन के लिए डीबग जानकारी निकाल देता है। – Rudi

उत्तर

5

मैं तुम्हें घोषित करने के लिए अपने ML_COMMENT एक विशेष रूप हालत शुरू की जरूरत है स्थिति शुरू करें ताकि केवल ML_COMMENT नियम सक्रिय हों।%x ML_COMMENT%s ML_COMMENT

अन्यथा कोई प्रारंभिक स्थिति वाले नियम भी सक्रिय हैं।

+0

आह! ऐसा लगता है कि चाल चल रही है। मेरा एकमात्र सवाल यह है कि: मेरी बहु-पंक्ति टिप्पणियों की सामग्री क्यों प्रतिबिंबित होती है? जब मैं एसटीडीआईएन में '/ * foo bar * /' टाइप करता हूं, तो मुझे STDOUT पर मुद्रित 'foo bar' मिलता है। – adelarge

+2

[। \ N] ऐसा नहीं कर रहा है जो आप सोचते हैं। इसके लिए 2 नियमों के साथ प्रतिस्थापित करें। और एक के लिए \ n। डिफ़ॉल्ट echos इनपुट द्वारा फ्लेक्स जो किसी भी नियम से मेल नहीं खाता है। यही कारण है कि कई lex नियम सेट "।" के साथ समाप्त होता है। इसलिए हर इनपुट कुछ मेल खाता है। – Craig

+0

उसने ऐसा किया। धन्यवाद! – adelarge

5

टिप्पणी पार्स इस तरह त्रुटियों का कारण बन सकता है क्योंकि:

  • आप अपने लेक्स सभी नियमों का
  • तो यह और भी अधिक जटिल हो जाता है, तो आप भी संभाल करने // चाहते हैं कि स्थिति को जोड़ने की आवश्यकता टिप्पणी
  • आपको अभी भी जोखिम है कि yacc/bison

मेरे पार्सर में, मैं इस तरह की टिप्पणियां संभालता हूं। सबसे पहले इस तरह, टिप्पणी की शुरुआत के लिए लेक्स नियमों को परिभाषित:

\/\*  { 
     if (!SkipComment()) 
      return(-1); 
     } 

\/\/  { 
     if (!SkipLine()) 
      return(-1); 
     } 

तो SkipComment और SkipLine कार्यों लिखें। वे सभी इनपुट उपभोग करने के लिए जब तक टिप्पणी के अंत में पाया जाता है की जरूरत है (यह नहीं बल्कि है पुराने कोड तो मेरे कुछ हद तक पुराने निर्माणों को माफ):

bool SkipComment (void) 
{ 
int Key; 

Key=!EOF; 
while (true) 
    { 
    if (Key==EOF) 
     { 
     /* yyerror("Unexpected EOF within comment."); */ 
     break; 
     } 
    switch ((char)Key) 
     { 
     case '*' : 
     Key=input(); 
     if (char)Key=='/') return true; 
     else    continue; 
     break; 
     case '\n' : 
     ++LineNr; 
     break; 
     } 
    Key=input(); 
    } 

return false; 
} 

bool SkipLine (void) 
{ 
int Key; 

Key=!EOF; 
while (true) 
    { 
    if (Key==EOF) 
     return true; 
    switch ((char)Key) 
     { 
     case '\n' : 
     unput('\n'); 
     return true; 
     break; 
     } 
    Key=input(); 
    } 

return false; 
} 
+1

क्या यह टिप्पणी प्रारंभ/अंत वर्ण अनुक्रम को संभालता है यदि यह उद्धृत पाठ के भीतर होता है? (उदा। 'foo = "इसमें कोई/* टिप्पणी नहीं है * /" ') –

+0

मैंने स्पष्ट रूप से इसका उल्लेख नहीं किया है, लेकिन आपको तारों को बिल्कुल उसी तरह से पार्स करना होगा। यदि आप सी/सी ++ में बैकस्लैश से बचने का समर्थन करना चाहते हैं तो आपको विशेष रूप से ऐसा करना होगा। – Patrick

+1

यह अधिक जटिल, अधिक त्रुटि प्रवण, अधिक verbose, और ठीक से फ्लेक्स शुरू राज्यों का उपयोग करने के बजाय करने के लिए कठिन है। यह मूल रूप से आपके लेक्सर का हाथ-लेखन हिस्सा है - अगर आपको फ्लेक्स पसंद नहीं है, तो क्यों न सिर्फ पूरी चीज़ को हाथ से लिखो? –

1

%x बनाम %s के साथ समस्या के अलावा, आप भी समस्या यह है कि .[.\n] में मैच (केवल) एक शाब्दिक . न कि 'किसी भी चरित्र न्यू लाइन के अलावा अन्य' एक नंगे . की तरह करता है। आप

<ML_COMMENT>.|"\n"  { /* do nothing */ } 

जैसा कोई नियम के बजाय

1

मैं सी भाषा व्याकरण (वास्तव में सिर्फ lexer) बहुत उपयोगी इस विवरण पाया चाहते हैं। मुझे लगता है कि यह ज्यादातर पैट्रिक के जवाब के समान है, लेकिन थोड़ा अलग है।

http://www.lysator.liu.se/c/ANSI-C-grammar-l.html

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