Jison / Flex: Попытка перехватить что-нибудь (.*) Между двумя токенами, но возникли проблемы

В настоящее время я работаю над небольшим маленьким DSL, мало чем отличающимся от Rabl. Я борюсь с выполнением одного из моих правил. Прежде чем мы перейдем к проблеме, я немного объясню свой синтаксис / грамматику. На моем небольшом языке вы можете определить свойства, блоки объекта / массива или пользовательские блоки (все они используются для создания объекта / массива json). "Пользовательским блоком" может быть либо блок, содержащий мои стандартные выражения (свойство, блок объекта / массива и т. Д.), Либо некоторый JavaScript. Эти выражения написаны как таковые -

-- An object block
object @model

    -- A property node
    property some, key(name="value")

    -- A custom node
    object custom_obj as 
        property some(name="key")
    end

    -- A custom script node
    property full_name as (u)
        // This is JavaScript
        return u.first_name + ' ' + u.last_name;
    end
end 

Проблема, с которой я сталкиваюсь, связана с моим пользовательским узлом сценария. У меня очень трудно определить токен скрипта, чтобы JISON мог правильно захватить содержимое внутри блока. В моем лексере у меня сейчас есть...

# script_param is basically a regex to match "(some_ident)"
{script_param}  { this.begin('js'); return 'SCRIPT_PARAM'; }
<js>(.|\n|\r)*?"end" %{ 
    this.popState();
    yytext = yytext.substr(0, yyleng - 3).trim();
    return 'SCRIPT';
%}

Этот токен SCRIPT в основном будет соответствовать чему угодно после (u) вплоть до (и включая) конечного токена (который обычно заканчивается блоком). Мне это очень не нравится, потому что мой обычный терминатор блока (конец) на самом деле является частью токена скрипта, который мне кажется совершенно взломанным. К сожалению, я не могу найти лучший способ уловить НИЧЕГО между (..) и концом. Я попытался написать регулярное выражение, которое захватывает все, что заканчивается ";", но это создает проблемы, когда у меня есть несколько узлов сценария в моем коде dsl. Я только смог сделать эту работу, включив ключевое слово "end" как часть моего захвата.

Вот ссылки на мои файлы грамматики и лексера.

Я был бы очень признателен за понимание моей проблемы! Если я не объяснил свою проблему четко, дайте мне знать, и я сделаю все возможное, чтобы уточнить! Спасибо заранее!!

Я также с радостью приму любой совет, как очистить мою грамматику. Я все еще новичок в этом деле и чувствую, что мои вещи сейчас беспорядок:)

1 ответ

Решение

Достаточно просто сопоставить строку, но не включая первый экземпляр end:

([^e]|e[^n]|en[^d])*

(И это даже не нуждается в жадном повторении.)

Однако это не то, что вы хотите. Включенный JavaScript может включать в себя:

  • переменные, имена которых включают символы end (tendency)

  • Комментарии (/* Take the values up to the end of the line */)

  • строки символов (if (word == "end"))

  • и, действительно, слово end сам, который не является зарезервированным словом в JS.

Действительно, единственное чистое решение - это возможность использовать lex javascript. К счастью, вам не нужно делать это точно, потому что вы не интерпретируете это, но даже это немного работы. Самая раздражающая часть лексизации javascript, как и другие подобные языки, - это определение, когда / является началом регулярного выражения, а когда это просто деление; Чтобы получить это право, требуется большая часть анализатора JavaScript, особенно потому, что он также взаимодействует с правилом точки с запятой.

Чтобы справиться с тем фактом, что включенный JavaScript может фактически использовать переменную с именем endу вас есть несколько вариантов, насколько я вижу:

  1. Документируйте тот факт, что end это зарезервированное слово.

  2. Только распознать end когда он появляется вне скобок и в месте, где может начаться оператор (не слишком сложно, если вы в конечном итоге создадите достаточно синтаксического анализатора JS для правильной идентификации регулярных выражений)

  3. Только распознать end когда он появляется сам по себе на линии.

Последний вариант действительно сильно упростит вашу проблему, так что вы можете подумать об этом, хотя на самом деле это не очень элегантно.

Другие вопросы по тегам