diff options
author | Ryo Nihei <nihei.dev@gmail.com> | 2022-04-21 21:22:12 +0900 |
---|---|---|
committer | Ryo Nihei <nihei.dev@gmail.com> | 2022-04-21 21:22:12 +0900 |
commit | 0aa3e53b50649052371edc9c09b470a63f889371 (patch) | |
tree | 396993cf0d2a4a92eafed4b594535077a0ac1892 | |
parent | Update README (diff) | |
download | urubu-0aa3e53b50649052371edc9c09b470a63f889371.tar.gz urubu-0aa3e53b50649052371edc9c09b470a63f889371.tar.xz |
vartan-show command prints only adopted actions when conflicts occur
-rw-r--r-- | driver/parser.go | 5 | ||||
-rw-r--r-- | grammar/parsing_table.go | 88 | ||||
-rw-r--r-- | grammar/symbol.go | 17 | ||||
-rw-r--r-- | grammar/symbol_test.go | 4 |
4 files changed, 51 insertions, 63 deletions
diff --git a/driver/parser.go b/driver/parser.go index 4c7397f..e8d9968 100644 --- a/driver/parser.go +++ b/driver/parser.go @@ -377,11 +377,6 @@ func (p *Parser) searchLookahead(state int) []string { continue } - if term == p.gram.EOF() { - kinds = append(kinds, "<eof>") - continue - } - if alias := p.gram.TerminalAlias(term); alias != "" { kinds = append(kinds, alias) } else { diff --git a/grammar/parsing_table.go b/grammar/parsing_table.go index 0b858fb..a908001 100644 --- a/grammar/parsing_table.go +++ b/grammar/parsing_table.go @@ -300,12 +300,7 @@ func (b *lrTableBuilder) genDescription(tab *ParsingTable, gram *Grammar) (*spec var terms []*spec.Terminal { termSyms := b.symTab.terminalSymbols() - terms = make([]*spec.Terminal, len(termSyms)+2) - - terms[symbolEOF.num()] = &spec.Terminal{ - Number: symbolEOF.num().Int(), - Name: "<eof>", - } + terms = make([]*spec.Terminal, len(termSyms)+1) for _, sym := range termSyms { name, ok := b.symTab.toText(sym) @@ -435,60 +430,51 @@ func (b *lrTableBuilder) genDescription(tab *ParsingTable, gram *Grammar) (*spec }) var shift []*spec.Transition - var goTo []*spec.Transition - for sym, kID := range s.next { - nextState := b.automaton.states[kID] - if sym.isTerminal() { - shift = append(shift, &spec.Transition{ - Symbol: sym.num().Int(), - State: nextState.num.Int(), - }) - } else { - goTo = append(goTo, &spec.Transition{ - Symbol: sym.num().Int(), - State: nextState.num.Int(), - }) - } - } - - sort.Slice(shift, func(i, j int) bool { - return shift[i].State < shift[j].State - }) - - sort.Slice(goTo, func(i, j int) bool { - return goTo[i].State < goTo[j].State - }) - var reduce []*spec.Reduce - for _, item := range s.items { - if !item.reducible { - continue - } - - syms := make([]int, len(item.lookAhead.symbols)) - i := 0 - for a := range item.lookAhead.symbols { - syms[i] = a.num().Int() - i++ + var goTo []*spec.Transition + { + TERMINALS_LOOP: + for _, t := range b.symTab.terminalSymbols() { + act, next, prod := tab.getAction(s.num, t.num()) + switch act { + case ActionTypeShift: + shift = append(shift, &spec.Transition{ + Symbol: t.num().Int(), + State: next.Int(), + }) + case ActionTypeReduce: + for _, r := range reduce { + if r.Production == prod.Int() { + r.LookAhead = append(r.LookAhead, t.num().Int()) + continue TERMINALS_LOOP + } + } + reduce = append(reduce, &spec.Reduce{ + LookAhead: []int{t.num().Int()}, + Production: prod.Int(), + }) + } } - sort.Slice(syms, func(i, j int) bool { - return syms[i] < syms[j] - }) - - prod, ok := gram.productionSet.findByID(item.prod) - if !ok { - return nil, fmt.Errorf("failed to generate states: reducible production not found: %v", item.prod) + for _, n := range b.symTab.nonTerminalSymbols() { + ty, next := tab.getGoTo(s.num, n.num()) + if ty == GoToTypeRegistered { + goTo = append(goTo, &spec.Transition{ + Symbol: n.num().Int(), + State: next.Int(), + }) + } } - reduce = append(reduce, &spec.Reduce{ - LookAhead: syms, - Production: prod.num.Int(), + sort.Slice(shift, func(i, j int) bool { + return shift[i].State < shift[j].State }) - sort.Slice(reduce, func(i, j int) bool { return reduce[i].Production < reduce[j].Production }) + sort.Slice(goTo, func(i, j int) bool { + return goTo[i].State < goTo[j].State + }) } sr := []*spec.SRConflict{} diff --git a/grammar/symbol.go b/grammar/symbol.go index ee58737..6e357bb 100644 --- a/grammar/symbol.go +++ b/grammar/symbol.go @@ -60,6 +60,9 @@ const ( symbolStart = symbol(maskNonTerminal | maskStartOrEOF | symbolNumStart) // 0100 0000 0000 0001 symbolEOF = symbol(maskTerminal | maskStartOrEOF | symbolNumEOF) // 1100 0000 0000 0001: The EOF symbol is treated as a terminal symbol. + // The symbol name contains `<` and `>` to avoid conflicting with user-defined symbols. + symbolNameEOF = "<eof>" + nonTerminalNumMin = symbolNum(2) // The number 1 is used by a start symbol. terminalNumMin = symbolNum(2) // The number 1 is used by the EOF symbol. symbolNumMax = symbolNum(0xffff) >> 2 // 0011 1111 1111 1111 @@ -161,11 +164,15 @@ type symbolTable struct { func newSymbolTable() *symbolTable { return &symbolTable{ - text2Sym: map[string]symbol{}, - sym2Text: map[symbol]string{}, + text2Sym: map[string]symbol{ + symbolNameEOF: symbolEOF, + }, + sym2Text: map[symbol]string{ + symbolEOF: symbolNameEOF, + }, termTexts: []string{ - "", // Nil - "", // EOF + "", // Nil + symbolNameEOF, // EOF }, nonTermTexts: []string{ "", // Nil @@ -228,7 +235,7 @@ func (t *symbolTable) toText(sym symbol) (string, bool) { func (t *symbolTable) terminalSymbols() []symbol { syms := make([]symbol, 0, t.termNum.Int()-terminalNumMin.Int()) for sym := range t.sym2Text { - if !sym.isTerminal() || sym.isNil() || sym.isEOF() { + if !sym.isTerminal() || sym.isNil() { continue } syms = append(syms, sym) diff --git a/grammar/symbol_test.go b/grammar/symbol_test.go index 0cf2a06..747def9 100644 --- a/grammar/symbol_test.go +++ b/grammar/symbol_test.go @@ -23,8 +23,8 @@ func TestSymbol(t *testing.T) { } termTexts := []string{ - "", // Nil - "", // EOF + "", // Nil + symbolNameEOF, // EOF "id", "add", "mul", |