Как правильно сканировать идентификаторы с помощью Ragel - PullRequest
4 голосов
/ 06 марта 2011

Я пытаюсь написать сканер для моего C / C ++ / C # / Java / D-подобного языка программирования, который я проектирую по личным причинам.Для этой задачи я использую Ragel для генерации моего сканера.У меня возникают проблемы с пониманием, когда именно многие операторы инициируют действия, возможно, потому, что мои ученые были сосредоточены на практических знаниях, а не на теории, и значительная часть этого недетерминированного / детерминированного бизнеса с конечными автоматами идет мне на ум.Я считаю, что документация либо отсутствует, либо мое понимание таковым является.Я предполагаю последнее.

В любом случае, я работаю над тем, чтобы уйти от основ.Я определил несколько ключевых слов и специальных символов в моей первой итерации.Теперь я столкнулся с проблемой, когда все ключевые слова сканируются как идентификаторы.Я использую оператор сканера для всех своих ключевых слов, поскольку это решило мою проблему проверки строки returns как ключевого слова return и returns.

Как правильно выполнить сканирование дляидентификаторы?Я понимаю, что для того, чтобы сделать это детерминированным, мне нужно эффективно указать, что лексема может быть identifier, только если она не соответствует ни одному шаблону токена.Прости меня за отсутствие знаний.

Ragel Сценарий:

%%{
    Identifier = (alpha | '_') . (alnum | '_')*;
    action IdentifierAction
    {
        std::cout << "identifier(\"";
        std::cout.write(ts, te - ts);
        std::cout << "\")";
    }
}%%

%%{
    main :=
    |*
        Interface => InterfaceAction;
        Class => ClassAction;
        Property => PropertyAction;
        Function => FunctionAction;
        TypeQualifier => TypeQualifierAction;
        OpenParenthesis => OpenParenthesisAction;
        CloseParenthesis => CloseParenthesisAction;
        OpenBracket => OpenBracketAction;
        CloseBracket => CloseBracketAction;
        OpenBrace => OpenBraceAction;
        CloseBrace => CloseBraceAction;
        Semicolon => SemicolonAction;
        Returns => ReturnsAction;
        Return => ReturnAction;
        Identifier => IdentifierAction;
        space+;
    *|;
}%%

1 Ответ

6 голосов
/ 14 марта 2011

Не знаком с Ragel, но сделал несколько пользовательских анализаторов и сканеров.

Похоже, ваш вопрос больше связан с обнаружением ключевых слов, чем с определением общих идентификаторов.

У вас есть правила, предписывающие Ragel определять, когда в разделе есть код, число, ключевое слово «return», точка с запятой, ключевое слово «return», идентификатор и так далее. Хотя для каждого ключевого слова можно создать правило, я не рекомендую.

Что я узнал на собственном опыте, так это то, что лучше читать все ключевые слова эксплицитность в качестве идентификаторов (назначить общий маркер "идентификатора"), а в какой-то части вашего кода C / C ++ определить, какие идентификаторы являются «ключевыми словами».

Другими словами. Ragel будет обнаруживать только идентификаторы. «myvar», «return» и «return» будут помечены как «идентификаторы». Позже, в коде вашего семантического действия ( C / C ++ не Ragel ), вы проверите каждый идентификатор и определите, является ли ключевое слово в C / C ++. Обычно это делается с помощью списка ключевых слов.

Я думаю, что это будет примерно так:

%%{
Identifier = (alpha | '_') . (alnum | '_')*;
action IdentifierAction
{
    String Keywords[] = 
    (
       "return",
       "if",
       "else"
    ); 

    String MyIdentifier = te - ts;
    if (SearchKeywordCode(Keywords, MyIdentifier)) {
      std::cout << "keyword(\"";
      std::cout.write(ts, te - ts);
      std::cout << "\")";
    }
    else {
      std::cout << "identifier(\"";
      std::cout.write(ts, te - ts);
      std::cout << "\")";
    }
}
}%%

Таким образом, не существует правила «Возврат» или «Возврат», а только «Идентификатор».

...