diff --git a/Grammar/grammar.go b/Grammar/grammar.go index 6c9912d..2a0fe0e 100644 --- a/Grammar/grammar.go +++ b/Grammar/grammar.go @@ -86,6 +86,8 @@ func (g *Grammar) CalculateEpsilonClosure() { if every_isEpsilon { if !(r.LeftPart.IsEpsilonClosure) { r.LeftPart.IsEpsilonClosure = true + // epsilon is terminate too + r.LeftPart.CanTerminate = true change++ } } @@ -95,6 +97,47 @@ func (g *Grammar) CalculateEpsilonClosure() { } } } + +//calculate all epsilon +func (g *Grammar) CalculateCanTerminate() []*symbol.Symbol { + change := 0 + for { + change = 0 + for _, r := range g.ProductoinRules { + //for every sym in RightPart, is IsEpsilonClosure, Is EpsilonClosure + //empty is true + every_CanTerm := true + for _, every_sy := range r.RighPart { + every_CanTerm = every_CanTerm && every_sy.CanTerminate + } + if every_CanTerm { + if !(r.LeftPart.CanTerminate) { + r.LeftPart.CanTerminate = true + change++ + } + } + } + if change == 0 { + break + } + } + var inf_cycles []*symbol.Symbol + for sy := range g.VnSet { + if !sy.CanTerminate { + inf_cycles = append(inf_cycles, sy) + } + } + return inf_cycles +} + +func (g Grammar) PrintInfLoop(some []*symbol.Symbol) { + fmt.Println("Error:") + for _, s := range some { + fmt.Printf("%s ", s.Name) + } + fmt.Println(" have Infinite recursion loop") +} + func (g Grammar) ShowAllSymbols() { for _, s := range g.Symbols { s.Show() diff --git a/Parser/Parser_test.go b/Parser/Parser_test.go index f50f75d..3ca25bc 100644 --- a/Parser/Parser_test.go +++ b/Parser/Parser_test.go @@ -168,6 +168,7 @@ func TestParser2(t *testing.T) { %start s %% s : A + ` if tr, err := Parse(str); err != nil { t.Error(err) @@ -233,3 +234,36 @@ func TestParser3(t *testing.T) { root.LALR1 = lalr } } + +func TestParserInifLoop(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("The code did not panic") + } + }() + str := ` + %{ + package main + %} + + %left A B +%left C +%start s +%% +s : A +A : B +B : A + %% +` + if tr, err := Parse(str); err != nil { + t.Error(err) + } else { + // work in test + var node Node = tr + w := DoWalker(&node, &RootVistor{}) + lalr := w.BuildLALR1() + fmt.Println(lalr) + root := w.VistorNode.(*RootVistor) + root.LALR1 = lalr + } +} diff --git a/Parser/Vistor.go b/Parser/Vistor.go index bd0d860..9b270c0 100644 --- a/Parser/Vistor.go +++ b/Parser/Vistor.go @@ -122,9 +122,8 @@ func (v *astDeclareVistor) Process(node *Node) { Value: 0, } v.idsymtabl[n.StartSym] = id - v.startSym = v.idsymtabl[n.StartSym] } - + v.startSym = v.idsymtabl[n.StartSym] //set other value v.code = n.CodeList v.union = n.Union @@ -319,6 +318,11 @@ func (w *Walker) BuildLALR1() *lalr.LALR1 { } g.ResolveSymbols() g.CalculateEpsilonClosure() + if infLoop := g.CalculateCanTerminate(); len(infLoop) != 0 { + g.PrintInfLoop(infLoop) + panic("Dected infinite loop") + } + item_var := item.NewItem(0, 0) Icloures := item.NewItemCloure() Icloures.InsertItem(item_var) diff --git a/Symbol/symbol.go b/Symbol/symbol.go index 3f9613e..9dcbd1a 100644 --- a/Symbol/symbol.go +++ b/Symbol/symbol.go @@ -21,12 +21,13 @@ type Symbol struct { Tag string // Tag indicate the type of symbol IsNonTerminator bool IsEpsilonClosure bool + CanTerminate bool //check weather is has inf loop PrecType E_Precedence Prec int } func NewSymbol(id uint, name string) *Symbol { - return &Symbol{ID: id, Name: name, PrecType: NONE, Prec: -1} + return &Symbol{ID: id, Name: name, PrecType: NONE, Prec: -1, CanTerminate: true} } func (s *Symbol) SetValue(val int) { @@ -43,6 +44,7 @@ func (s *Symbol) GetTag() string { func (s *Symbol) SetNT() { s.IsNonTerminator = true + s.CanTerminate = false } func (s *Symbol) SetEpsilon() {