2010-07-21 2 views
2

Как фильтровать последовательность токенов, исходящих от моего Lexer, до моего анализатора при использовании комбинаторов парсера Scala?Фильтрация токенов от компиляторов Scala Parser

Позвольте мне объяснить - предположим, что у меня довольно стандартный образец Lexer (расширение StdLexical) и анализатор (расширение StdTokenParsers). Лексер превращает последовательность символов в последовательность токенов, затем парсер превращает последовательность токенов в абстрактное синтаксическое дерево (типа Expr).

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

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

Пример кода ток:

val reader = new PagedSeqReader(PagedSeq.fromReader(reader)) 
val tokens = new MyParser.lexical.Scanner(reader) 
val parse = MyParser.phrase(parser)(tokens) 

Я хотел бы быть в состоянии написать что-то вроде этого:

val reader = new PagedSeqReader(PagedSeq.fromReader(reader)) 
val tokens = new MyParser.lexical.Scanner(reader) 
val parse = MyParser.phrase(parser)(filter(tokens)) 

ответ

1

Рассматривали ли вы использованием RegexParsers, чтобы удалить пробелы и комментарии?

EDIT

Вы можете сделать простой фильтр

import scala.util.parsing.input._ 

object ReaderFilter { 
    def filter[T](reader: Reader[T], check: T => Boolean): Reader[T] = { 
    new Reader[T] { 
     var orig = reader 
     def first = { trim; orig.first } 
     def atEnd = { trim; orig.atEnd } 
     def rest: Reader[T] = { trim; ReaderFilter.filter(orig.rest, check) } 
     def pos = orig.pos 
     private def trim = { 
     while (!orig.atEnd && !check(orig.first)) 
      orig = orig.rest 
     } 
    } 
    } 
} 

и использовать его таким образом (чтобы удалить маркеры, которые являются "#"):

val tokens = ReaderFilter.filter(new MyParser.lexical.Scanner(reader), 
      {t:ExprParser.lexical.Token => t.chars != "#"}) 
+0

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

+0

Я сам написал это, потом вернулся и понял, что вы отредактировали! Вы можете принять принятый ответ, интересно, как код настолько похож. Я использовал рекурсию, и вы использовали цикл while, но, кроме того, они почти одинаковы :-) –

2

Я Вы сделали это сейчас, вот результаты. Ключевым понятием является то, что анализатор из комбинатора парсеров использует вход scala.util.parsing.input.Reader. Поэтому нам нужен класс, который обертывает Reader, и сам по себе является Reader, который отфильтровывает записи при некотором условии.

Я пишу Reader, поэтому на строительстве он пропускает все нежелательные записи и останавливается либо в первой хорошей записи, либо в конце. Затем каждый вызов делегируется оригинальному считывателю, за исключением rest, который, в свою очередь, строит другой TokenFilter.

import scala.util.parsing.input._ 

class Filter[T](parent : Reader[T], exclude : T=>Boolean) extends Reader[T] { 
    private val start = nextOk(parent) 
    def nextOk(r : Reader[T]) : Reader[T] = 
    if(r.atEnd) r else (if (exclude(r.first)) nextOk(r.rest) else r) 

    override def source = start.source 
    override def offset: Int = start.offset 
    override def first: T = start.first 
    override def rest: Reader[T] = new Filter(start.rest, exclude) 
    override def pos: Position = start.pos 
    override def atEnd = start.atEnd 
} 
Смежные вопросы