Skip to content

Commit

Permalink
Merge pull request #3 from acekingke/PackTable
Browse files Browse the repository at this point in the history
Parser: use packed sparse matrix for state table #2
  • Loading branch information
acekingke authored Feb 16, 2022
2 parents 816ab35 + b1967f5 commit 584d9d5
Show file tree
Hide file tree
Showing 8 changed files with 300 additions and 4 deletions.
10 changes: 8 additions & 2 deletions Builder/GoGenCode.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,14 @@ func GoGenFromString(input string, file string) error {
b := NewGoBuilder(w)
b.buildConstPart()
b.buildUionAndCode()
b.buildAnalyTable()
b.buildStateFunc()
if b.vnode.NeedPacked {
b.buildAnalyPackTable()
b.buildPackStateFunc()
} else {
b.buildAnalyTable()
b.buildStateFunc()
}

b.buildReduceFunc()
b.buildTranslate()
// Create file and write to it
Expand Down
112 changes: 112 additions & 0 deletions Builder/GoGenPackTableCode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package builder

import "fmt"

// make AnalyTable
func (b *GoBuilder) buildAnalyPackTable() {
AnalyTable := `
var StatePackAction = []int {
%s
}
var StatePackOffset = []int {
%s
}
var StackPackCheck = []int {
%s
}
`
saction := ""
soffset := ""
scheck := ""
for _, val := range b.vnode.ActionTable {
saction += fmt.Sprintf("%d,\t", val)
}
for _, val := range b.vnode.OffsetTable {
soffset += fmt.Sprintf("%d,\t", val)
}
for _, val := range b.vnode.CheckTable {
scheck += fmt.Sprintf("%d,\t", val)
}
b.AnalyTable = fmt.Sprintf(AnalyTable, saction, soffset, scheck)
}

func (b *GoBuilder) buildPackStateFunc() {
b.StateFunc = `
// Push StateSym
func PushStateSym(state *StateSym) {
if StackPointer >= len(StateSymStack) {
StateSymStack = append(StateSymStack, *state)
} else {
StateSymStack[StackPointer] = *state
}
StackPointer++
}
// Pop num StateSym
func PopStateSym(num int) {
StackPointer -= num
}
func (s *StateSym) Action(a int) int {
if StatePackOffset[s.Yystate]+a >= len(StackPackCheck) || StackPackCheck[StatePackOffset[s.Yystate]+a] != s.Yystate {
return 0
}else{
return StatePackAction[StatePackOffset[s.Yystate]+a]
}
}
func init() {
StateSymStack = []StateSym{
{
Yystate: 0,
YySymIndex: 1, //$
},
}
StackPointer = 1
}
func Parser(input string) *ValType {
var currentPos int = 0
var val ValType
lookAhead := fetchLookAhead(input, &val, &currentPos)
for {
if StackPointer == 0 {
break
}
if StackPointer > len(StateSymStack) {
break
}
s := &StateSymStack[StackPointer-1]
a := s.Action(lookAhead)
if a == ERROR_ACTION {
panic("Grammer error")
} else if a == ACCEPT_ACTION {
return &s.ValType
} else {
if a > 0 {
// shift
PushStateSym(&StateSym{
Yystate: a,
YySymIndex: lookAhead,
ValType: val,
})
lookAhead = fetchLookAhead(input, &val, &currentPos)
} else {
reduceIndex := -a
SymTy := ReduceFunc(reduceIndex)
s := &StateSymStack[StackPointer-1]
gotoState := s.Action(SymTy.YySymIndex)
SymTy.Yystate = gotoState
PushStateSym(SymTy)
}
}
}
return nil
}
func fetchLookAhead(input string, val *ValType, pos *int) int {
token := GetToken(input, val, pos)
return translate(token)
}
`
}
21 changes: 21 additions & 0 deletions LALR/LALR.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"sort"

grammar "github.com/acekingke/yaccgo/Grammar"

utils "github.com/acekingke/yaccgo/Utils"
)

Expand All @@ -21,6 +22,11 @@ type LALR1 struct {
FollowSet,
LookAheadSet map[int][]int
NumOfStates int //States number
// The last is for pack table
NeedPacked bool
ActionTable []int
OffsetTable []int
CheckTable []int
}

// q --t--> p
Expand Down Expand Up @@ -276,7 +282,22 @@ func ComputeLALR(g *grammar.Grammar) *LALR1 {
panic(err.Error())
} else {
lalr.GTable = tab
// try to pack the table
act, off, check := utils.PackTable(lalr.GTable)
lalr.NeedPacked = false
lalr.NumOfStates = len(lalr.G.LR0.LR0Closure)
if len(act)+len(off)+len(check) > lalr.NumOfStates*len(lalr.G.Symbols) {
if utils.DebugFlags {
fmt.Println("The table is no need to pack")
}
} else {
if utils.DebugFlags {
fmt.Println("The table is packed")
}
lalr.NeedPacked = true
lalr.ActionTable, lalr.OffsetTable, lalr.CheckTable = act, off, check
}

}
return lalr
}
8 changes: 8 additions & 0 deletions LALR/LALR_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
item "github.com/acekingke/yaccgo/Items"
rule "github.com/acekingke/yaccgo/Rules"
symbol "github.com/acekingke/yaccgo/Symbol"
utils "github.com/acekingke/yaccgo/Utils"
)

func TestUnion(t *testing.T) {
Expand Down Expand Up @@ -368,6 +369,13 @@ func TestLALR1_ambiguity(t *testing.T) {
}
fmt.Println("},")
}
act, off, check := utils.PackTable(tab)
if len(act)+len(off)+len(check) > len(lalr.G.LR0.LR0Closure)*len(lalr.G.Symbols) {
fmt.Println("The table is no need to pack")
} else {
fmt.Println("The table is packed")

}
}

}
4 changes: 3 additions & 1 deletion Parser/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ Use of this source code is governed by MIT license that can be found in the LICE
*/
package parser

import "strings"
import (
"strings"
)

func genTempName(in string) string {
return "$operator" + in
Expand Down
93 changes: 93 additions & 0 deletions Utils/packtable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package utils

import "sort"

type Pair struct {
a, b interface{}
}

// Use Tarjan and Yao method compress the two-dimensional array
func PackTable(table [][]int) ( /*T*/ []int /*D*/, []int /*Check*/, []int) {
var row []int
entry := make([]bool, len(table)*len(table[0]))
//step 1 count every row non-zero element
rowCount := []Pair{}
for i := 0; i < len(table); i++ {
rowCount = append(rowCount, Pair{i, 0})
for j := 0; j < len(table[i]); j++ {
if table[i][j] != 0 {
rowCount[i].b = rowCount[i].b.(int) + 1
}
}
row = append(row, 0)
}
//step 2 fetch all non-zero element position
nonZeroPos := make(map[int][]int) // list(i)
for i := 0; i < len(table); i++ {
for j := 0; j < len(table[i]); j++ {
if table[i][j] != 0 {
nonZeroPos[i] = append(nonZeroPos[i], j)
}
}
}
//step 3 compress
//sort the count
sort.SliceStable(rowCount, func(i, j int) bool {
return rowCount[i].b.(int) > rowCount[j].b.(int)
})
maxIndex := 0
// from the largest to the smallest
for _, p := range rowCount {
i := p.a.(int)
row[i] = 0
//check overlap
checkoverlap:
for _, j := range nonZeroPos[i] {
if entry[row[i]+j] {
row[i]++
goto checkoverlap
}
}
for _, k := range nonZeroPos[i] {
entry[row[i]+k] = true
if maxIndex < row[i]+k {
maxIndex = row[i] + k
}
}
}
var ret []int = make([]int, maxIndex+1)
var check []int = make([]int, maxIndex+1)
//init check with -1
for i := 0; i < maxIndex+1; i++ {
check[i] = -1
}
//step 4 output
for i, js := range nonZeroPos {
for _, k := range js {
ret[row[i]+k] = table[i][k]
check[row[i]+k] = i
}
}
return ret, row, check
}

func UnPackTable(rows int, cols int, T []int, D []int, C []int) [][]int {
var table [][]int = make([][]int, rows)
// step 1 find the maxIndex

// step 2 allocate the table
for i := 0; i < len(table); i++ {
table[i] = make([]int, cols)
}
// step 3 fill the table
for i := 0; i < len(D); i++ {
for j := 0; j < cols; j++ {
if D[i]+j >= len(C) || C[D[i]+j] != i {
table[i][j] = 0
} else {
table[i][j] = T[D[i]+j]
}
}
}
return table
}
52 changes: 52 additions & 0 deletions Utils/packtable_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
Copyright (c) 2021 Ke Yuchang([email protected]). All rights reserved.
Use of this source code is governed by MIT license that can be found in the LICENSE file.
*/
package utils

import (
"fmt"
"reflect"
"testing"
)

func TestPackTable1(t *testing.T) {
table := [][]int{
{0, 0, 1, 2, 0, 0},
{0, 0, 1, 2, 0, 0},
{9, 0, 0, 0, 0, 8},
{0, 10, 0, 0, 0, 0},
{9, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 11, 0},
{0, 0, 1, 2, 0, 0},
{0, 0, 1, 2, 11, 0},
{0, 10, 0, 0, 0, 0},
}
fmt.Println(table)
T, D, C := PackTable(table)
fmt.Println(T)
fmt.Println(D)
fmt.Println(C)
R := UnPackTable(9, 6, T, D, C)
if !reflect.DeepEqual(table, R) {
t.Error("PackTable1 failed")
}

}

func TestPackTable2(t *testing.T) {
table := [][]int{
{1, 0, 0},
{0, 1, 0},
{0, 0, 1},
}
fmt.Println(table)
T, D, C := PackTable(table)
fmt.Println(T)
fmt.Println(D)
fmt.Println(C)
R := UnPackTable(3, 3, T, D, C)
if !reflect.DeepEqual(table, R) {
t.Error("PackTable2 failed")
}
}
4 changes: 3 additions & 1 deletion examples/ladd.y
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
%%
PROG:
/*empty*/
| PROG E NL
| PROG E NL {
fmt.Println($2)
}
E:
E PLUS E {
$$ = $1 + $3
Expand Down

0 comments on commit 584d9d5

Please sign in to comment.