Skip to content

Commit

Permalink
*: refactor the pack
Browse files Browse the repository at this point in the history
  • Loading branch information
keyuchang committed May 26, 2022
1 parent 89b3fe7 commit d608322
Show file tree
Hide file tree
Showing 14 changed files with 805 additions and 42 deletions.
2 changes: 1 addition & 1 deletion Builder/GoGenCode.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (b *GoBuilder) buildConstPart() {
b.ConstPart += fmt.Sprintf("const %s = %d\n", identifier.Name, identifier.Value)
}
}
b.ConstPart += fmt.Sprintf("const ERROR_ACTION = 0\nconst ACCEPT_ACTION = %d\n", b.vnode.GenAcceptCode())
b.ConstPart += fmt.Sprintf("const ERROR_ACTION = %d\nconst ACCEPT_ACTION = %d\n", b.vnode.GenErrorCode(), b.vnode.GenAcceptCode())
}

func (b *GoBuilder) buildUionAndCode() {
Expand Down
6 changes: 5 additions & 1 deletion Builder/GoGenPackTableCode.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/*
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 builder

import "fmt"
Expand Down Expand Up @@ -49,7 +53,7 @@ func PopStateSym(num int) {
}
func (s *StateSym) Action(a int) int {
if StatePackOffset[s.Yystate]+a >= len(StackPackCheck) || StackPackCheck[StatePackOffset[s.Yystate]+a] != s.Yystate {
if StatePackOffset[s.Yystate]+a < 0|| StatePackOffset[s.Yystate]+a >= len(StackPackCheck) || StackPackCheck[StatePackOffset[s.Yystate]+a] != s.Yystate {
return 0
}else{
return StatePackAction[StatePackOffset[s.Yystate]+a]
Expand Down
188 changes: 188 additions & 0 deletions Builder/GoTemplBuilder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package builder

import (
"fmt"
"os"
"text/template"

parser "github.com/acekingke/yaccgo/Parser"
)

type TemplateBuilder struct {
vnode *parser.RootVistor
NeedPacked bool
NTerminals int
HeaderPart string
CodeHeader string
ConstPart string
UnionPart string
AnalyTable string
PackAnalyTable string
CodeLast string
StateFunc string
ReduceFunc string
Translate string
TranslateTrace string
ReduceTrace string
}

func TemplateGenFromString(input string, file string) error {
w, err := parser.ParseAndBuild(input)
if err != nil {
return fmt.Errorf("parse error: %s", err)
}
b := NewTemplateBuilder(w)
b.buildConstPart()
b.buildUionAndCode()
b.buildAnalyTable()
b.buildStateFunc()
b.buildReduceFunc()
b.buildTranslate()
// Create file and write to it
f, err := os.Create(file)
if err != nil {
return fmt.Errorf("create file error: %s", err)
}

b.WriteFile(f)
return nil
}

func NewTemplateBuilder(w *parser.Walker) *TemplateBuilder {
return &TemplateBuilder{
HeaderPart: `/*Generator Code , do not modify*/\n`,
vnode: w.VistorNode.(*parser.RootVistor),
}
}

func (b *TemplateBuilder) buildConstPart() {
b.NeedPacked = b.vnode.NeedPacked
b.NTerminals = len(b.vnode.G.VtSet)
b.CodeHeader = b.vnode.GetCode()
b.CodeLast = b.vnode.GetCodeCopy()
for _, identifier := range b.vnode.GetIdsymtabl() {
if identifier.IDTyp == parser.TERMID &&
!parser.TestPrefix(identifier.Name) {
b.ConstPart += fmt.Sprintf("const %s = %d\n", identifier.Name, identifier.Value)
}
}
}

func (b *TemplateBuilder) buildUionAndCode() {
b.UnionPart = b.vnode.GetUion()
}

func (b *TemplateBuilder) buildAnalyTable() {
if !b.NeedPacked {
s := "/* "
for _, sy := range b.vnode.G.Symbols {
s += fmt.Sprintf("%s\t", sy.Name)
}
s += "*/\n"
for index, row := range b.vnode.GTable {
s += fmt.Sprintf("/* %d */ {", index)
for _, val := range row {
s += fmt.Sprintf("%d,\t", val)
}
s += "},\n"
}
b.AnalyTable = s
} else {
AnalyTable := `
var StatePackAction = []int {
%s
}
var StatePackOffset = []int {
%s
}
var StackPackCheck = []int {
%s
}
var StackPackActDef = []int {
%s
}
var StackPackGotoDef = []int {
%s
}
`
saction := ""
soffset := ""
scheck := ""
sactdef := ""
sgotodef := ""
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)
}
for _, val := range b.vnode.ActionDef {
sactdef += fmt.Sprintf("%d,\t", val)
}
for _, val := range b.vnode.GoToDef {
sgotodef += fmt.Sprintf("%d,\t", val)
}
b.PackAnalyTable = fmt.Sprintf(AnalyTable, saction, soffset, scheck, sactdef, sgotodef)
}
}

func (b *TemplateBuilder) buildStateFunc() {
}

func (b *TemplateBuilder) buildReduceFunc() {
caseCode := ""
for i := 1; i < len(b.vnode.G.ProductoinRules); i++ {
productionRule := b.vnode.G.ProductoinRules[i]
caseCode += fmt.Sprintf("case %d: \n", i)
rightPartlen := len(productionRule.RighPart)
caseCode += fmt.Sprintf("\tdollarDolar.YySymIndex = %d\n", productionRule.LeftPart.ID)
caseCode += fmt.Sprintf("\tDollar := StateSymStack[topIndex-%d : StackPointer]\n\t_ = Dollar\n", rightPartlen)
//fetch the action code here
caseCode += actionCodeReplace(b.vnode, i, productionRule)
caseCode += fmt.Sprintf("\tPopStateSym(%d)\n", rightPartlen)
}
b.ReduceFunc = caseCode
}

func (b *TemplateBuilder) buildTranslate() {
caseCodes := ""
for _, sy := range b.vnode.G.Symbols {
if !sy.IsNonTerminator {
caseCodes += fmt.Sprintf("\tcase %d:\n \tconv = %d\n", sy.Value, sy.ID)
}
}
b.Translate = caseCodes
caseCodes = ""
for _, sy := range b.vnode.G.Symbols {
caseCodes += fmt.Sprintf("\tcase %d:\n \tconv = \"%s\"\n", sy.ID, parser.RemoveTempName(sy.Name))
}
b.TranslateTrace = caseCodes
caseCode := ""
for i := 1; i < len(b.vnode.G.ProductoinRules); i++ {
caseCode += fmt.Sprintf("\t\tcase %d: \n", i)
oneRule := b.vnode.GetRules(i - 1)
leftPartString := "use Reduce:" + parser.RemoveTempName(oneRule.LeftPart.Name)
var rightPartString string = ""
for _, rightPart := range oneRule.RighPart {
rightPartString += parser.RemoveTempName(rightPart.Name) + " "
}
strTrace := fmt.Sprintf("%s -> %s",
leftPartString, rightPartString)
caseCode += fmt.Sprintf("\n\t\tfmt.Printf(\"look ahead %%s, %s, go to state %%d\\n\", look, s)\n", strTrace)
}
b.ReduceTrace = caseCode
}

func (b *TemplateBuilder) WriteFile(f *os.File) {
templ, err := template.ParseFiles("goCode.templ")
defer f.Close()
if err != nil {
fmt.Println(err)
}
if err := templ.Execute(f, b); err != nil {
panic(err)
}
}
181 changes: 181 additions & 0 deletions Builder/GoTemplBuilder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package builder

import "testing"

func TestTemplateGenFromString(t *testing.T) {
str := `// language: go
%{
package main
import (
"fmt"
)
%}
%union {
val int
}
%type <val> E
%token '+' '*' '(' ')'
%left '+'
%left '*'
%token <val> NUM
%token NUM 100
%start E
%%
E:
E '+' E {
$$ = $1 + $3
}
| E '*' E {
$$ = $1 * $3
}
| '(' E ')' {
$$ = $2
}
| NUM {
$$ = $1
}
%%
const EOF = -1
// The parser expects the lexer to return 0 on EOF. Give it a name
// for clarity.
func GetToken(input string, valTy *ValType, pos *int) int {
if *pos >= len(input) {
return -1
} else {
*valTy = ValType{0}
loop:
if *pos >= len(input) {
return EOF
}
c := input[*pos]
*pos++
switch c {
case '+':
fallthrough
case '(':
fallthrough
case ')':
fallthrough
case '*':
return int(c)
default:
if c >= '0' && c <= '9' { // is digit
valTy.val = (valTy.val)*10 + int(c) - '0'
// next is digit
if *pos < len(input) && input[*pos] >= '0' && input[*pos] <= '9' {
goto loop
}
return NUM
}
}
return 0
}
}
func main() {
v := Parser("1+2*31").val
fmt.Println(v)
}
`
err := TemplateGenFromString(str, "../../sample3.go")
if err != nil {
t.Error(err)
}
}

func TestTemplateGenFromString2(t *testing.T) {
str := `// language: go
%{
package main
import (
"fmt"
)
%}
%union {
val int
}
%type <val> E
%token PLUS NL
%token <val> NUM
%token NUM 100
%start PROG
%left PLUS
%%
PROG:
/*empty*/
| PROG E NL {
fmt.Println($2)
}
E:
E PLUS E {
$$ = $1 + $3
}
| NUM {
$$ = $1
}
%%
const EOF = -1
// The parser expects the lexer to return 0 on EOF. Give it a name
// for clarity.
func GetToken(input string, valTy *ValType, pos *int) int {
if *pos >= len(input) {
return -1
} else {
*valTy = ValType{0}
loop:
if *pos >= len(input) {
return EOF
}
c := input[*pos]
*pos++
switch c {
case '+':
return PLUS
case '\n':
return NL
default:
if c >= '0' && c <= '9' { // is digit
valTy.val = (valTy.val)*10 + int(c) - '0'
// next is digit
if *pos < len(input) && input[*pos] >= '0' && input[*pos] <= '9' {
goto loop
}
return NUM
}
}
return 0
}
}
func main() {
v := Parser("1+2\n").val
fmt.Println(v)
}
`
err := TemplateGenFromString(str, "../../sample2.go")
if err != nil {
t.Error(err)
}
}
Loading

0 comments on commit d608322

Please sign in to comment.