сложность получения комментариев в стиле c в flex / lex - PullRequest
29 голосов
/ 25 января 2010

Я хочу создать в flex правило для потребления комментария в стиле c, например / * * /

у меня есть следующее

c_comment "/*"[\n.]*"*/"

Но это никогда не подходит. Есть идеи почему? если вам нужно больше моего кода, пожалуйста, дайте мне знать, и я отправлю все это. Спасибо всем, кто отвечает.

Ответы [ 8 ]

41 голосов
/ 25 января 2010

Я предлагаю вам использовать условия запуска .

%x C_COMMENT

"/*"            { BEGIN(C_COMMENT); }
<C_COMMENT>"*/" { BEGIN(INITIAL); }
<C_COMMENT>\n   { }
<C_COMMENT>.    { }

Обратите внимание, что не должно быть пробелом между <condition> и правилом.

%x C_COMMENT определяет состояние C_COMMENT, и правило /* имеет его начало. После запуска */ вернет его в исходное состояние (предварительно определено INITIAL), а все остальные символы будут просто использованы без каких-либо особых действий. Когда два правила совпадают, Flex устраняет неоднозначность, беря то, которое имеет самое длинное соответствие, поэтому правило точки не препятствует совпадению */. Правило \n необходимо, потому что точка соответствует всему, кроме новой строки .

Определение %x делает C_COMMENT исключительным состоянием , что означает, что лексер будет соответствовать правилам, которые «помечены» <C_COMMENT>, только когда он войдет в состояние.

Вот крошечный лексер , который реализует этот ответ, печатая все, кроме того, что внутри /* comments */.

9 голосов
/ 29 января 2013

Вот пример на всякий случай, если кто-то не понимает, как работает ответ zneak:

(По сути, вы помещаете "% x C_COMMENT" в первый раздел, а остальные во второй раздел, как объясняется его полезной ссылкой)

foo.l

%{
// c code..
%}
%x C_COMMENT

%%
"/*"            { BEGIN(C_COMMENT); }
<C_COMMENT>"*/" { BEGIN(INITIAL); }
<C_COMMENT>.    { }

%%
// c code..

Надеюсь, это кому-нибудь поможет! Tiff

7 голосов
/ 25 января 2010

Не знаю, почему его не подбирают, но я знаю, что шаблон такого типа может создавать большие лексические элементы. Более эффективно обнаруживать только маркер начального комментария и бросать все в битовую корзину, пока не найдете маркер конца.

Этот сайт имеет код, который сделает это:

"/*" {
    for (;;) {
        while ((c = input()) != '*' && c != EOF)
            ; /* eat up text of comment */
        if (c == '*') {
            while ((c = input()) == '*')
                ;
            if (c == '/')
                break; /* found the end */
        }
        if (c == EOF) {
            error ("EOF in comment");
            break;
        }
    }
}
2 голосов
/ 14 ноября 2012

Я считаю, что это решение проще:

"/*"((\*+[^/*])|([^*]))*\**"*/"
1 голос
/ 25 сентября 2016

Есть рабочий пример в руководстве по Flex , в котором правильно рассматриваются крайние случаи:

<INITIAL>"/*"         BEGIN(IN_COMMENT);
<IN_COMMENT>"*/"      BEGIN(INITIAL);
<IN_COMMENT>[^*\n]+   // eat comment in chunks
<IN_COMMENT>"*"       // eat the lone star
<IN_COMMENT>\n        yylineno++;
0 голосов
/ 18 ноября 2014

"/*"(.|\n)"*/" измените ваше регулярное выражение на это, оно будет работать наверняка.

0 голосов
/ 24 июля 2014

Я попробовал несколько из предложенных решений, и вот результаты.

  • Я не смог заставить решение C_COMMENT, которое имеет наибольшее количество голосов и выглядит великолепно, работать на практике вообще (один из комментариев объясняет хотя бы одну причину) Оно должно быть отвергнуто и, конечно, не должно быть решением с наибольшим количеством голосов
  • Решение от Mugen, похоже, работало во всем коде, на котором я его запускал
  • Не удалось получить решение от Андрея, чтобы он вообще компилировался в lex. Я посмотрел на указанный веб-сайт, и использование шаблонов оттуда не помогло
  • ответ от paxdiablo работал и имел преимущество в том, что его было легко читать. Я далее изменил следующим образом:

    "/*" { int c1 = 0, c2 = input();
           for(;;) {
             if(c2 == EOF) break;
             if(c1 == '*' && c2 == '/')
               break;
             c1 = c2;
             c2 = input();
           }
         }
    
0 голосов
/ 08 августа 2013

Сработал пример:

\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\/

найдено в ostermiller.org

...