Я создаю DSL и использую библиотеку синтаксического анализатора Scala для анализа DSL. DSL придерживается простого, подобного Ruby синтаксиса. Исходный файл может содержать серию блоков, которые выглядят так:
create_model do
at 0,0,0
end
Окончания строк имеют важное значение в DSL, поскольку они эффективно используются в качестве разделителей операторов.
Я написал парсер Scala, который выглядит так:
class ML3D extends JavaTokenParsers {
override val whiteSpace = """[ \t]+""".r
def model: Parser[Any] = commandList
def commandList: Parser[Any] = rep(commandBlock)
def commandBlock: Parser[Any] = command~"do"~eol~statementList~"end"
def eol: Parser[Any] = """(\r?\n)+""".r
def command: Parser[Any] = commandName~opt(commandLabel)
def commandName: Parser[Any] = ident
def commandLabel: Parser[Any] = stringLiteral
def statementList: Parser[Any] = rep(statement)
def statement: Parser[Any] = functionName~argumentList~eol
def functionName: Parser[Any] = ident
def argumentList: Parser[Any] = repsep(argument, ",")
def argument: Parser[Any] = stringLiteral | constant
def constant: Parser[Any] = wholeNumber | floatingPointNumber
}
Поскольку окончания строк имеют значение, я переопределил whiteSpace
, чтобы он обрабатывал только пробелы и символы табуляции как пробел (вместо того, чтобы рассматривать новые строки как пробел и, следовательно, игнорировать их).
Это работает, за исключением оператора "end" для commandBlock
. Поскольку мой исходный файл содержит завершающую новую строку, анализатор жалуется, что ожидал просто end
, но получил новую строку после ключевого слова end
.
Поэтому я изменил определение commandBlock
на следующее:
def commandBlock: Parser[Any] = command~"do"~eol~statementList~"end"~opt(eol)
(то есть я добавил необязательную новую строку после «end»).
Но теперь при разборе исходного файла я получаю следующую ошибку:
[4.1] failure: `end' expected but `' found
Я думаю это потому, что после того, как он высосет завершающую новую строку, синтаксический анализатор обнаружит пустую строку, которую он считает недействительной, но я не уверен, почему он это делает.
Какие-нибудь советы, как это исправить? Я мог бы расширить неправильный парсер из библиотеки комбинатора парсера Scala, поэтому любые предложения о том, как создать определение языка со значительными символами новой строки, также приветствуются.