2010-07-26 5 views
9

मैं सरल टेम्पलेट भाषा के लिए एक पार्सर पर काम कर रहा हूं। मैं रागेल का उपयोग कर रहा हूँ।रैगेल में टेम्पलेट भाषाओं का विश्लेषण कैसे करें?

आवश्यकताएं मामूली हैं। मैं [[टैग]] ढूंढने की कोशिश कर रहा हूं जिसे इनपुट स्ट्रिंग में कहीं भी एम्बेड किया जा सकता है।

मैं एक साधारण टेम्पलेट भाषा का विश्लेषण करने की कोशिश कर रहा हूं, जिसमें कुछ ऐसा हो सकता है जैसे {{foo}} HTML में एम्बेड किया गया हो। मैंने इसे पार्स करने के लिए कई दृष्टिकोणों की कोशिश की लेकिन उन्हें एक रैगेल स्कैनर का उपयोग करने का सहारा लेना पड़ा और केवल एक ही चरित्र से मिलान करने के अक्षम दृष्टिकोण का उपयोग "सभी को पकड़ो" के रूप में करना था। मुझे लगता है कि इस बारे में जाने का यह गलत तरीका है। मैं अनिवार्य रूप से अपने डिफ़ॉल्ट नियम को लागू करने के लिए स्कैनर की सबसे लंबी मैच पूर्वाग्रह का दुरुपयोग कर रहा हूं (यह केवल 1 चार लंबा हो सकता है, इसलिए यह हमेशा अंतिम उपाय होना चाहिए)।

%%{ 

    machine parser; 

    action start  { tokstart = p; }   
    action on_tag  { results << [:tag, data[tokstart..p]] }    
    action on_static { results << [:static, data[p..p]] }    

    tag = ('[[' lower+ ']]') >start @on_tag; 

    main := |* 
    tag; 
    any  => on_static; 
    *|; 

}%% 

(रूबी में लिखे गए कार्यों, लेकिन समझने में आसान होना चाहिए)।

आप इतनी सरल भाषा के लिए एक पार्सर लिखने के बारे में कैसे जाएंगे? क्या रैगेल शायद सही उपकरण नहीं है? ऐसा लगता है कि अगर आपको वाक्यविन्यास इस तरह अप्रत्याशित है तो आपको रागल दांत और नाखूनों से लड़ना होगा।

उत्तर

20

रैगेल ठीक काम करता है। आप जो भी मेल खाते हैं उसके बारे में आपको सावधान रहना होगा। आपका प्रश्न [[tag]] और {{tag}} दोनों का उपयोग करता है, लेकिन आपका उदाहरण [[tag]] का उपयोग करता है, इसलिए मुझे लगता है कि आप विशेष रूप से इलाज करने की कोशिश कर रहे हैं।

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

tag = '[[' lower+ ']]'; 

main := (
    (any - '[')* # eat text 
    ('[' ^'[' | tag) # try to eat a tag 
)*; 

मुश्किल हिस्सा है,:

ठीक है, कि इस मशीन के एक शब्दशः विवरण दिया गया है? मुझे लगता है कि करने के लिए सबसे अच्छा जवाब का दावा नहीं करते हैं, लेकिन यहाँ क्या मैं के साथ आया है:

static char *text_start; 

%%{ 
    machine parser; 

    action MarkStart { text_start = fpc; } 
    action PrintTextNode { 
    int text_len = fpc - text_start; 
    if (text_len > 0) { 
     printf("TEXT(%.*s)\n", text_len, text_start); 
    } 
    } 
    action PrintTagNode { 
    int text_len = fpc - text_start - 1; /* drop closing bracket */ 
    printf("TAG(%.*s)\n", text_len, text_start); 
    } 

    tag = '[[' (lower+ >MarkStart) ']]' @PrintTagNode; 

    main := (
    (any - '[')* >MarkStart %PrintTextNode 
    ('[' ^'[' %PrintTextNode | tag) >MarkStart 
)* @eof(PrintTextNode); 
}%% 

कुछ अस्पष्ट बातें कर रहे हैं:

  • eof कार्रवाई क्योंकि %PrintTextNode की जरूरत है केवल मशीन छोड़ने पर ही आह्वान किया जाता है। यदि इनपुट सामान्य पाठ के साथ समाप्त होता है, तो उस स्थिति को छोड़ने के लिए कोई इनपुट नहीं होगा। चूंकि यह इनपुट टैग के साथ समाप्त होने पर भी बुलाया जाएगा, और कोई अंतिम, अप्रकाशित टेक्स्ट नोड, PrintTextNode परीक्षण है कि इसमें प्रिंट करने के लिए कुछ पाठ है।
  • हालांकि हम, जब हम [ मारा शुरुआत को चिह्नित किया के बाद हम एक गैर [ मारा, हम कुछ भी फिर से पार्स और प्रारंभ बिंदु टिप्पणी करने की कोशिश कर शुरू करेंगे %PrintTextNode कार्रवाई ^'[' बाद में बसे क्योंकि, की जरूरत है। ऐसा होने से पहले हमें उन दो पात्रों को फ्लश करने की ज़रूरत है, इसलिए कार्रवाई का आह्वान।

पूर्ण पार्सर निम्नानुसार है।मैं सी में यह किया क्योंकि मैं जानता हूँ कि, लेकिन आप जो कुछ भी भाषा आप बहुत आसानी से की जरूरत है यह में बदलने के लिए सक्षम होना चाहिए:

/* ragel so_tag.rl && gcc so_tag.c -o so_tag */ 
#include <stdio.h> 
#include <string.h> 

static char *text_start; 

%%{ 
    machine parser; 

    action MarkStart { text_start = fpc; } 
    action PrintTextNode { 
    int text_len = fpc - text_start; 
    if (text_len > 0) { 
     printf("TEXT(%.*s)\n", text_len, text_start); 
    } 
    } 
    action PrintTagNode { 
    int text_len = fpc - text_start - 1; /* drop closing bracket */ 
    printf("TAG(%.*s)\n", text_len, text_start); 
    } 

    tag = '[[' (lower+ >MarkStart) ']]' @PrintTagNode; 

    main := (
    (any - '[')* >MarkStart %PrintTextNode 
    ('[' ^'[' %PrintTextNode | tag) >MarkStart 
)* @eof(PrintTextNode); 
}%% 

%% write data; 

int 
main(void) { 
    char buffer[4096]; 
    int cs; 
    char *p = NULL; 
    char *pe = NULL; 
    char *eof = NULL; 

    %% write init; 

    do { 
    size_t nread = fread(buffer, 1, sizeof(buffer), stdin); 
    p = buffer; 
    pe = p + nread; 
    if (nread < sizeof(buffer) && feof(stdin)) eof = pe; 

    %% write exec; 

    if (eof || cs == %%{ write error; }%%) break; 
    } while (1); 
    return 0; 
} 

यहाँ कुछ परीक्षण इनपुट है:

[[header]] 
<html> 
<head><title>title</title></head> 
<body> 
<h1>[[headertext]]</h1> 
<p>I am feeling very [[emotion]].</p> 
<p>I like brackets: [ is cool. ] is cool. [] are cool. But [[tag]] is special.</p> 
</body> 
</html> 
[[footer]] 

और यहाँ उत्पादन है पार्सर से:

TAG(header) 
TEXT(
<html> 
<head><title>title</title></head> 
<body> 
<h1>) 
TAG(headertext) 
TEXT(</h1> 
<p>I am feeling very) 
TAG(emotion) 
TEXT(.</p> 
<p>I like brackets:) 
TEXT([) 
TEXT(is cool. ] is cool.) 
TEXT([]) 
TEXT(are cool. But) 
TAG(tag) 
TEXT(is special.</p> 
</body> 
</html> 
) 
TAG(footer) 
TEXT(
) 

अंतिम टेक्स्ट नोड में फ़ाइल के अंत में केवल नई लाइन होती है।

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