Недавно я достаточно увлекся LALR, чтобы написать генератор LALR и Я пытаюсь построить для него грамматику в стиле java или c # (начало которой указано здесь).
Я знаю, что написание генератора синтаксического анализатора требует дополнительных усилий, например, заново изобретать колесо (почему бы не использовать Antlr?), Но моя цель - создать хобби-ОС, которая может компилироваться сама по себе, независимо от сторонней инструментальной цепочки. Моя проблема, правда, не в генераторе, а в грамматике.
Я сталкиваюсь с уменьшением / уменьшением двусмысленности с утверждениями и выражениями.
Я знаю, как разрешить определенные типы неоднозначности, такие как висячие и другие, но эти немногие из них не интуитивно понятны для меня, и они поставили меня в тупик.
Как лучше всего их решить? Кроме того, есть ли инструмент для создания прототипов, который я могу использовать для визуализации решения? Или мне следует вернуться к исходной точке и попробовать реализовать генератор парсера GLR для грамматики?
Эти заявления являются законными:
Generic.List<int> myVar1 = x + 4, myVar2; // stmt -> var-decl ;
// var-decl -> type-name var-decl-list
t = 99; // simple-stmt -> assign
i++; // simple-stmt -> incr-decr
// incr-decr -> primary-expr ++
json.deserialize<list<int>>(obj); // simple-stmt -> call
// call -> primary-expr ( params )
// ... -> primary-expr . basic-name ( params )
// ... -> basic-name . basic-name ( params )
Вот как это устроено:
basic-name : ident < type-list >
| ident
nested-name : nested-name . basic-name
| basic-name
basic-type : int | bool | ...
type-name : nested-name
| basic-type
stmt : var-decl ;
| simple-stmt ;
| ...
var-decl : type-name var-decl-list
var-decl-list : var-decl-list , var-init
| var-init
var-init : ident assign-op expression
| ident
simple-stmt : assign
| call
| incr-decr
expr : assign-expr
assign-expr : assign
| cond-expr
assign : unary-expr assign-op expr
...
rel-expr : rel-expr < shift-expr
...
| shift-expr
...
unary-expr : unary-op primary-expr
| primary-expr
unary-op : + - ! ~ ++ -- // Prefix operators
| ( type-name ) // Conversion operator
primary-expr : call
| primary-expr . basic-name
| primary-expr ++
| ( expr )
...
| basic-name
call : primary-expr ( params )
incr-decr : primary-expr ++
| -- primary-expr
| ...
Поэтому, когда синтаксический анализатор ожидает оператор, ядро набора элементов * LR (k) равно method-body -> { * stmts-opt }
, а полный набор элементов для состояния выглядит примерно так:
method-body -> { * stmts-opt }
stmts-opt -> * stmts
stmts-opt -> *
stmts -> * stmts stmt
stmt -> * var-decl ;
stmt -> * simple-stmt ;
var-decl -> * type-name var-decl-list
simple-stmt -> * assign
simple-stmt -> * call
simple-stmt -> * incr-decr
type-name -> * nested-name
type-name -> * basic-type
nested-name -> * nested-name . basic-name
nested-name -> * basic-name
basic-name -> * ident < type-list >
basic-name -> * ident
assign -> * unary-expr assign-op expr
unary-expr -> * unary-op primary-expr
unary-expr -> * primary-expr
unary-op -> * ( typename )
unary-op -> * ! | ~ | ...
primary-expr -> * call
primary-expr -> * primary-expr . basic-name
primary-expr -> * primary-expr ++
primary-expr -> * basic-name
primary-expr -> * ( expr )
call -> * primary-expr ( params )
incr-decr -> * primary-expr ++
...
При смещении идентификатора следующее состояние:
basic-name -> ident *
basic-name -> ident * < type-list >
который разбирается или сокращается и приводит к следующему состоянию:
nested-name -> basic-name *
primary-expr -> basic-name *
Возможный конфликт. В родительском состоянии предварительный просмотр не помогает, поскольку в nested-name
и primary-expr
есть точка. Ой, хорошо, давай попробуем сократить по вложенному имени:
type-name -> nested-name *
nested-name -> nested-name * . basic-name
Здесь не на что смотреть ... А как насчет того, чтобы вместо этого уменьшить на primary-expr
:
unary-expr -> primary-expr *
primary-expr -> primary-expr * . basic-name
primary-expr -> primary-expr * ++
call -> primary-expr * ( params )
incr-decr -> primary-expr * ++
...
Теперь, когда мы сдвигаем ++, мы получаем:
primary-expr -> primary-expr ++ *
incr-decr -> primary-expr ++ *
... еще один конфликт уменьшения-уменьшения.
Попробуем сместить (
вместо ident
:
primary-expr -> ( * expr )
unary-op -> ( * type-name )
expr -> * assign-expr
assign-expr -> * assign
assign-expr -> * cond-expr
assign -> * unary-expr assign-op expr
unary-expr -> * unary-op primary-expr
unary-expr -> * primary-expr
unary-op -> * ( typename )
unary-op -> * ! | ~ | ...
primary-expr -> * call
primary-expr -> * primary-expr . basic-name
primary-expr -> * primary-expr ++
primary-expr -> * basic-name
primary-expr -> * ( expr )
call -> * primary-expr ( params )
cond-expr -> * ...
...
rel-expr -> * rel-expr < shift-expr
rel-expr -> * shift-expr
...
type-name -> * nested-name
type-name -> * basic-type
nested-name -> * nested-name . basic-name
nested-name -> * basic-name
basic-name -> * ident < type-list >
basic-name -> * ident
Те же проблемы, когда вы перекладываете ident
или (
в стек.
Это как раз те, с которыми я пока сталкивался. Поскольку basic-name
имеет приоритет над rel-expr
, я предполагаю, что что-то вроде x < n
будет интерпретировано как basic-name -> ident < type-list *
, и выйдет ошибка, если это действительно было реляционное выражение.
Мой мозг достиг точки, когда мне действительно нужна помощь.
rel-expr
извлекаетbasic-name
за очень много шагов, я говорю, что он имеет более высокий приоритет. - person Josh Wyant   schedule 10.08.2015<
для rel-expr, мы должны уменьшитьident
доbasic-name
, а затем доrel-expr
, чтобы перейти в состояниеrel-expr -> rel-expr * < shift-expr
. Если мы это сделаем, даже если полный ввод равенx < n > ( )
, мы уже уменьшили доrel-expr
:rel-expr * < n > ()
, и мы не сможем получить< type-list >
из следующих 3 токенов, потому что для этого мы должны получитьbasic-name -> ident < type-list > *
на стек, а неbasic-name -> rel-expr < type-list > *
. - person Josh Wyant   schedule 10.08.2015rel-expr -> ident * < shift-expr
иbasic-name -> ident * < type-list >
, потому что первый не является реальным продуктом. - person Josh Wyant   schedule 10.08.2015