aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyo Nihei <nihei.dev@gmail.com>2022-04-21 21:22:12 +0900
committerRyo Nihei <nihei.dev@gmail.com>2022-04-21 21:22:12 +0900
commit0aa3e53b50649052371edc9c09b470a63f889371 (patch)
tree396993cf0d2a4a92eafed4b594535077a0ac1892
parentUpdate README (diff)
downloadurubu-0aa3e53b50649052371edc9c09b470a63f889371.tar.gz
urubu-0aa3e53b50649052371edc9c09b470a63f889371.tar.xz
vartan-show command prints only adopted actions when conflicts occur
-rw-r--r--driver/parser.go5
-rw-r--r--grammar/parsing_table.go88
-rw-r--r--grammar/symbol.go17
-rw-r--r--grammar/symbol_test.go4
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",