diff --git a/cmd/vartan/show.go b/cmd/vartan/show.go index 920ba66..04fc4e2 100644 --- a/cmd/vartan/show.go +++ b/cmd/vartan/show.go @@ -14,9 +14,6 @@ import ( "github.com/spf13/cobra" ) -var showFlags = struct { -}{} - func init() { cmd := &cobra.Command{ Use: "show", @@ -150,7 +147,7 @@ func writeDescription(w io.Writer, desc *spec.Description) error { } if count == 1 { - return fmt.Sprintf("1 conflict was detected.") + return "1 conflict was detected." } else if count > 1 { return fmt.Sprintf("%v conflicts were detected.", count) } diff --git a/grammar/follow.go b/grammar/follow.go index f835bba..67e5f70 100644 --- a/grammar/follow.go +++ b/grammar/follow.go @@ -87,20 +87,6 @@ func (flw *followSet) find(sym symbol) (*followEntry, error) { return e, nil } -type followComContext struct { - prods *productionSet - first *firstSet - follow *followSet -} - -func newFollowComContext(prods *productionSet, first *firstSet) *followComContext { - return &followComContext{ - prods: prods, - first: first, - follow: newFollow(prods), - } -} - func genFollowSet(prods *productionSet, first *firstSet) (*followSet, error) { ntsyms := map[symbol]struct{}{} for _, prod := range prods.getAllProductions() { @@ -110,11 +96,11 @@ func genFollowSet(prods *productionSet, first *firstSet) (*followSet, error) { ntsyms[prod.lhs] = struct{}{} } - cc := newFollowComContext(prods, first) + follow := newFollow(prods) for { more := false for ntsym := range ntsyms { - e, err := cc.follow.find(ntsym) + e, err := follow.find(ntsym) if err != nil { return nil, err } @@ -138,7 +124,7 @@ func genFollowSet(prods *productionSet, first *firstSet) (*followSet, error) { more = true } if fst.empty { - flw, err := cc.follow.find(prod.lhs) + flw, err := follow.find(prod.lhs) if err != nil { return nil, err } @@ -155,43 +141,5 @@ func genFollowSet(prods *productionSet, first *firstSet) (*followSet, error) { } } - return cc.follow, nil -} - -func genFollowEntry(cc *followComContext, acc *followEntry, ntsym symbol) (bool, error) { - changed := false - - if ntsym.isStart() { - added := acc.addEOF() - if added { - changed = true - } - } - for _, prod := range cc.prods.getAllProductions() { - for i, sym := range prod.rhs { - if sym != ntsym { - continue - } - fst, err := cc.first.find(prod, i+1) - if err != nil { - return false, err - } - added := acc.merge(fst, nil) - if added { - changed = true - } - if fst.empty { - flw, err := cc.follow.find(prod.lhs) - if err != nil { - return false, err - } - added := acc.merge(nil, flw) - if added { - changed = true - } - } - } - } - - return changed, nil + return follow, nil } diff --git a/grammar/follow_test.go b/grammar/follow_test.go index ba2d973..af3f064 100644 --- a/grammar/follow_test.go +++ b/grammar/follow_test.go @@ -158,6 +158,9 @@ func genActualFollow(t *testing.T, src string) (*followSet, *Grammar) { t.Fatal(err) } flw, err := genFollowSet(gram.productionSet, fst) + if err != nil { + t.Fatal(err) + } if flw == nil { t.Fatal("genFollow returned nil without any error") } diff --git a/grammar/grammar.go b/grammar/grammar.go index 2294219..7dbd0ed 100644 --- a/grammar/grammar.go +++ b/grammar/grammar.go @@ -116,7 +116,7 @@ func (b *GrammarBuilder) Build() (*Grammar, error) { if len(md.Parameters) != 1 || md.Parameters[0].ID == "" { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrMDInvalidParam, - Detail: fmt.Sprintf("'name' takes just one ID parameter"), + Detail: "'name' takes just one ID parameter", Row: md.Pos.Row, Col: md.Pos.Col, }) @@ -480,7 +480,7 @@ func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, string, *ve if len(dir.Parameters) == 0 { return nil, false, "", &verr.SpecError{ Cause: semErrDirInvalidParam, - Detail: fmt.Sprintf("'mode' directive needs an ID parameter"), + Detail: "'mode' directive needs an ID parameter", Row: dir.Pos.Row, Col: dir.Pos.Col, }, nil @@ -489,7 +489,7 @@ func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, string, *ve if param.ID == "" { return nil, false, "", &verr.SpecError{ Cause: semErrDirInvalidParam, - Detail: fmt.Sprintf("'mode' directive needs an ID parameter"), + Detail: "'mode' directive needs an ID parameter", Row: param.Pos.Row, Col: param.Pos.Col, }, nil @@ -528,7 +528,7 @@ func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, string, *ve if len(dir.Parameters) > 0 { return nil, false, "", &verr.SpecError{ Cause: semErrDirInvalidParam, - Detail: fmt.Sprintf("'skip' directive needs no parameter"), + Detail: "'skip' directive needs no parameter", Row: dir.Pos.Row, Col: dir.Pos.Col, }, nil @@ -538,7 +538,7 @@ func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, string, *ve if len(dir.Parameters) != 1 || dir.Parameters[0].ID == "" { return nil, false, "", &verr.SpecError{ Cause: semErrDirInvalidParam, - Detail: fmt.Sprintf("'push' directive needs an ID parameter"), + Detail: "'push' directive needs an ID parameter", Row: dir.Pos.Row, Col: dir.Pos.Col, }, nil @@ -548,7 +548,7 @@ func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, string, *ve if len(dir.Parameters) > 0 { return nil, false, "", &verr.SpecError{ Cause: semErrDirInvalidParam, - Detail: fmt.Sprintf("'pop' directive needs no parameter"), + Detail: "'pop' directive needs no parameter", Row: dir.Pos.Row, Col: dir.Pos.Col, }, nil @@ -558,7 +558,7 @@ func genLexEntry(prod *spec.ProductionNode) (*mlspec.LexEntry, bool, string, *ve if len(dir.Parameters) != 1 || dir.Parameters[0].String == "" { return nil, false, "", &verr.SpecError{ Cause: semErrDirInvalidParam, - Detail: fmt.Sprintf("'alias' directive needs a string parameter"), + Detail: "'alias' directive needs a string parameter", Row: dir.Pos.Row, Col: dir.Pos.Col, }, nil @@ -762,7 +762,7 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd if len(dir.Parameters) != 1 || dir.Parameters[0].Tree == nil { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrDirInvalidParam, - Detail: fmt.Sprintf("'ast' directive needs a tree parameter"), + Detail: "'ast' directive needs a tree parameter", Row: dir.Pos.Row, Col: dir.Pos.Col, }) @@ -829,7 +829,7 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd if len(dir.Parameters) != 1 || dir.Parameters[0].ID == "" { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrDirInvalidParam, - Detail: fmt.Sprintf("'prec' directive needs an ID parameter"), + Detail: "'prec' directive needs an ID parameter", Row: dir.Pos.Row, Col: dir.Pos.Col, }) @@ -859,7 +859,7 @@ func (b *GrammarBuilder) genProductionsAndActions(root *spec.RootNode, symTabAnd if len(dir.Parameters) > 0 { b.errs = append(b.errs, &verr.SpecError{ Cause: semErrDirInvalidParam, - Detail: fmt.Sprintf("'recover' directive needs no parameter"), + Detail: "'recover' directive needs no parameter", Row: dir.Pos.Row, Col: dir.Pos.Col, }) @@ -1140,7 +1140,10 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, error return nil, err } - f.Write(d) + _, err = f.Write(d) + if err != nil { + return nil, fmt.Errorf("failed to write a description file: %w", err) + } } if len(b.conflicts) > 0 { diff --git a/grammar/parsing_table.go b/grammar/parsing_table.go index 28f6392..0b858fb 100644 --- a/grammar/parsing_table.go +++ b/grammar/parsing_table.go @@ -56,10 +56,6 @@ func newGoToEntry(state stateNum) goToEntry { return goToEntry(state) } -func (e goToEntry) isEmpty() bool { - return e == goToEntryEmpty -} - func (e goToEntry) describe() (GoToType, stateNum) { if e == goToEntryEmpty { return GoToTypeError, stateNumInitial diff --git a/grammar/production.go b/grammar/production.go index d4ea7a1..87b392f 100644 --- a/grammar/production.go +++ b/grammar/production.go @@ -58,10 +58,6 @@ func newProduction(lhs symbol, rhs []symbol) (*production, error) { }, nil } -func (p *production) equals(q *production) bool { - return q.id == p.id -} - func (p *production) isEmpty() bool { return p.rhsLen == 0 } diff --git a/grammar/symbol.go b/grammar/symbol.go index 3a7dfb6..ee58737 100644 --- a/grammar/symbol.go +++ b/grammar/symbol.go @@ -122,10 +122,7 @@ func (s symbol) isNonTerminal() bool { return false } kind, _, _, _ := s.describe() - if kind == symbolKindNonTerminal { - return true - } - return false + return kind == symbolKindNonTerminal } func (s symbol) isTerminal() bool { diff --git a/grammar/symbol_test.go b/grammar/symbol_test.go index fda3ddf..0cf2a06 100644 --- a/grammar/symbol_test.go +++ b/grammar/symbol_test.go @@ -4,15 +4,15 @@ import "testing" func TestSymbol(t *testing.T) { tab := newSymbolTable() - tab.registerStartSymbol("expr'") - tab.registerNonTerminalSymbol("expr") - tab.registerNonTerminalSymbol("term") - tab.registerNonTerminalSymbol("factor") - tab.registerTerminalSymbol("id") - tab.registerTerminalSymbol("add") - tab.registerTerminalSymbol("mul") - tab.registerTerminalSymbol("l_paren") - tab.registerTerminalSymbol("r_paren") + _, _ = tab.registerStartSymbol("expr'") + _, _ = tab.registerNonTerminalSymbol("expr") + _, _ = tab.registerNonTerminalSymbol("term") + _, _ = tab.registerNonTerminalSymbol("factor") + _, _ = tab.registerTerminalSymbol("id") + _, _ = tab.registerTerminalSymbol("add") + _, _ = tab.registerTerminalSymbol("mul") + _, _ = tab.registerTerminalSymbol("l_paren") + _, _ = tab.registerTerminalSymbol("r_paren") nonTermTexts := []string{ "", // Nil diff --git a/spec/lexer.go b/spec/lexer.go index 80beba0..ba64925 100644 --- a/spec/lexer.go +++ b/spec/lexer.go @@ -205,7 +205,7 @@ func (l *lexer) lexAndSkipWSs() (*token, error) { // The escape sequences in a pattern string are interpreted by the lexer, except for the \". // We must interpret the \" before passing them to the lexer because they are delimiters for // the pattern strings. - fmt.Fprintf(&b, strings.ReplaceAll(string(tok.Lexeme), `\"`, `"`)) + fmt.Fprint(&b, strings.ReplaceAll(string(tok.Lexeme), `\"`, `"`)) case KindIDEscapeSymbol: return nil, &verr.SpecError{ Cause: synErrIncompletedEscSeq, @@ -240,13 +240,13 @@ func (l *lexer) lexAndSkipWSs() (*token, error) { } switch tok.KindID { case KindIDCharSeq: - fmt.Fprintf(&b, string(tok.Lexeme)) + fmt.Fprint(&b, string(tok.Lexeme)) case KindIDEscapedQuot: // Remove '\' character. - fmt.Fprintf(&b, `'`) + fmt.Fprint(&b, `'`) case KindIDEscapedBackSlash: // Remove '\' character. - fmt.Fprintf(&b, `\`) + fmt.Fprint(&b, `\`) case KindIDEscapeSymbol: return nil, &verr.SpecError{ Cause: synErrIncompletedEscSeq, diff --git a/spec/parser.go b/spec/parser.go index 71ee50b..7f3d8f7 100644 --- a/spec/parser.go +++ b/spec/parser.go @@ -193,8 +193,6 @@ func (p *parser) parseMetaData() *DirectiveNode { p.errs = append(p.errs, specErr) p.skipOverTo(tokenKindNewline) - - return }() p.consume(tokenKindNewline) @@ -241,8 +239,6 @@ func (p *parser) parseFragment() *FragmentNode { p.errs = append(p.errs, specErr) p.skipOverTo(tokenKindSemicolon) - - return }() p.consume(tokenKindNewline) @@ -308,8 +304,6 @@ func (p *parser) parseProduction() *ProductionNode { p.errs = append(p.errs, specErr) p.skipOverTo(tokenKindSemicolon) - - return }() p.consume(tokenKindNewline) diff --git a/spec/syntax_error.go b/spec/syntax_error.go index f82186a..a35a90c 100644 --- a/spec/syntax_error.go +++ b/spec/syntax_error.go @@ -19,7 +19,6 @@ var ( synErrAutoGenID = newSyntaxError("you cannot define an identifier beginning with an underscore") synErrUnclosedTerminal = newSyntaxError("unclosed terminal") synErrUnclosedString = newSyntaxError("unclosed string") - synErrInvalidEscSeq = newSyntaxError("invalid escape sequence") synErrIncompletedEscSeq = newSyntaxError("incompleted escape sequence; unexpected EOF following a backslash") synErrEmptyPattern = newSyntaxError("a pattern must include at least one character") synErrEmptyString = newSyntaxError("a string must include at least one character")