2015-08-14 4 views
2

Я работаю с грамматикой Java15 и задаю пару вопросов о том, как работает парсер Rascal и почему некоторые вещи не работают. Учитывая конкретный синтаксис:Анализ, соответствие и ключевые слова

module tests::Concrete 

start syntax CompilationUnit = 
    compilationUnit: TypeDec* LAYOUTLIST 
    ; 

syntax TypeDec = 
    ClassDec 
    ; 

syntax ClassDec = 
    \class: ClassDecHead ClassBody 
    ; 

syntax ClassDecHead = 
    "class" Id 
    ; 

syntax ClassBody = 
    "{" ClassBodyDec* "}" 
    ; 

syntax ClassBodyDec = 
    ClassMemberDec 
    ; 

syntax ClassMemberDec = 
    MethodDec 
    ; 

syntax MethodDec = 
    \method: MethodDecHead 
    ; 

syntax MethodDecHead = 
    ResultType Id 
    ; 

syntax ResultType = 
    \void: "void" 
    ; 

syntax Id = 
    \id: [A-Z_a-z] !<< ID \ IDKeywords !>> [0-9A-Z_a-z] 
    ; 

keyword Keyword = 
    "void" 
    ; 

keyword IDKeywords = 
    "null" 
    | Keyword 
    ; 

lexical LAYOUT = 
    [\t-\n \a0C-\a0D \ ] 
    ; 

lexical ID = 
    [A-Z_a-z] [0-9A-Z_a-z]* 
    ; 

layout LAYOUTLIST = 
    LAYOUT* !>> [\t-\n \a0C-\a0D \ ] !>> ( [/] [*] ) !>> ( [/] [/] ) !>> "/*" !>> "//" 
    ; 

определение АСТ:

module tests::Abstract 

data Declaration = 
    \compilationUnit(list[Declaration] body) 
    | \package(ID name) 
    | \import(ID name) 
    | \class(ID name, list[Declaration] body) 
    | \method(Type ret, ID name) 
      ; 

data Type = 
    \void() 
    ; 

data ID = 
    \id(str id) 
    ; 

и драйвер для загрузки файлов:

module tests::Load 

import Prelude; 
import tests::Concrete; 
import tests::Abstract; 

public Declaration load(loc l) = implode(#Declaration, parse(#CompilationUnit, l)); 

Я нахожу некоторые странности в том, что на самом деле работает и что нет. Если взять программу:

class A { 

} 

Это разбирает, как ожидалось в: compilationUnit([ class(id("A"),[]) ]) Но разбор и построение AST узлов методов внутри класса, оказывается немного волосатые. Учитывая программу:

class A { 
    void f 
} 

это производит ошибку "Cannot find a constructor for Declaration". Если я изменить синтаксис быть:

syntax MethodDecHead = 
    ResultType 
    ; 

АСТ быть:

| \method(Type ret) 

Я могу получить дерево, я бы ожидать: compilationUnit([class(id("A"),[method(void())])])

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

В дополнение к этому, если я не добавляю LAYOUTLIST в конец производства start syntax, я получаю ParseError в любое время, когда пытаюсь читать из файла.

+0

Может также вставлять целые файлы примеров здесь. Seen достаточно мало – jurgenv

ответ

2

Правило производства ClassDec несовместимо с узлом AST class. Изменение его:

syntax ClassDec = \class: "class" Id "{" ClassBodyDec* "}" ; делает его более регулярным и изоморфными с AST узла class(ID name, list[Declaration])

Однако: имена должны всегда соответствовать, поэтому я хотел бы предложить изменения ID к Id в грамматике. Кроме того, ваш узел АСТ ожидает Declaration с, но в грамматике у вас есть ClassBodyDec.

Общие правила implode являются:

  • Нетерминальные соответствует типу ADT
  • этикеток Продукция соответствует ADT конструктора
  • Ключевые слова, операторы, расположение и т.д. пропускается.
  • Карта немаркированных лексических произведений для примитивов (str, int, real).
  • Маркированные лексики могут отображаться на строительной площадке, если вы хотите: lexical Id = id: [a-z]+, можете нанести на data Id = id(str x);
  • Если вы не назовите контекстно-свободные произведения, implode «просматривает их»: так что, если бы у меня было syntax A = B; syntax B = cons: "bla", то я могу использовать ADT: data A = cons().

(Эти правила описаны в Parsetree.rsc, https://github.com/cwi-swat/rascal/blob/master/src/org/rascalmpl/library/ParseTree.rsc)

+0

Отлично, спасибо @Tijs. У меня есть кое-что работающее, и я думаю, что теперь у меня есть инструменты для продвижения вперед и, надеюсь, выяснить остальное :) – josh

1

Я не эксперт по implode, поэтому я оставляю это на данный момент, но LAYOUTLIST происходит из-за того, как вызывается parse.

Каждых start нетерминальных определяются start Something = производит два вида, а именно: * нетерминальный сам Something и * обертка нетерминального имени start[Something].

Обертка автоматически/неявно определяется следующим образом:

syntax start[Something] = LAYOUTLIST before Something top LAYOUTLIST after; 

Так что, если вы хотите иметь пробелы и комментарии до и после вашей программы вы называете разбора, как так:

parse(#start[Something], yourLocation) 

И если вы не заинтересованы в сохранении комментариев или пробелов на более позднем этапе, то вы можете проецировать верхнее дерево следующим образом:

Something mySomething = parse(#start[Something], myLocation).top; 
+0

Отлично, спасибо! Где я могу посмотреть/с кем связаться, для получения дополнительной информации о 'implode'. У меня есть подозрение, что это связано с тем, как макет, идентификаторы и ключевые слова взаимодействуют с грамматикой. – josh

Смежные вопросы