سؤال

لقد كنت أعمل على محلل للغة قالب بسيط.أنا أستخدم راجل.

المتطلبات متواضعة.أحاول العثور على [[العلامات]] التي يمكن تضمينها في أي مكان في سلسلة الإدخال.

أحاول تحليل لغة قالب بسيطة ، شيء يمكن أن يكون علامات مثل {{فو}} جزءا لا يتجزأ من هتمل.حاولت عدة طرق لتحليل هذا ولكن كان على اللجوء إلى استخدام الماسح الضوئي راجل واستخدام نهج غير فعال من مطابقة فقط حرف واحد باعتباره"قبض على جميع".أشعر أن هذه هي الطريقة الخاطئة للقيام بذلك.أنا أساسا استغلال التحيز أطول مباراة من الماسح الضوئي لتنفيذ القاعدة الافتراضية (يمكن أن يكون فقط 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;
  *|;

}%%

(الإجراءات المكتوبة في روبي ، ولكن يجب أن تكون سهلة الفهم).

كيف يمكنك أن تذهب نحو كتابة محلل لمثل هذه اللغة البسيطة?هل راجل ربما ليس الأداة المناسبة?يبدو أن لديك لمحاربة الأسنان راجل والأظافر إذا كان بناء الجملة لا يمكن التنبؤ بها مثل هذا.

هل كانت مفيدة؟

المحلول

راجل يعمل بشكل جيد.تحتاج فقط إلى توخي الحذر بشأن ما تطابقه.يستخدم سؤالك على حد سواء [[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(
)

تحتوي عقدة النص النهائي على السطر الجديد فقط في نهاية الملف.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top