├── .editorconfig ├── .errcheck-ignore ├── .gitattributes ├── .github └── workflows │ └── build.yaml ├── .gitignore ├── .golangci.yml ├── LICENSE ├── Makefile ├── README.md ├── doc ├── .gitignore ├── gocc.jpg ├── gocc_user_guide.pdf ├── gocc_user_guide.tex ├── hl_design.pdf ├── makedoc.sh └── target_grammar.tex ├── example ├── .gitignore ├── Makefile ├── astx │ ├── Makefile │ ├── ast.bnf │ ├── ast │ │ └── ast.go │ ├── ast_test.go │ ├── doc.go │ ├── errors │ │ └── errors.go │ ├── lexer │ │ ├── acttab.go │ │ ├── lexer.go │ │ └── transitiontable.go │ ├── parser │ │ ├── action.go │ │ ├── actiontable.go │ │ ├── context.go │ │ ├── gototable.go │ │ ├── parser.go │ │ └── productionstable.go │ ├── token │ │ ├── context.go │ │ └── token.go │ └── util │ │ ├── litconv.go │ │ └── rune.go ├── bools │ ├── Makefile │ ├── README │ ├── ast │ │ └── ast.go │ ├── doc.go │ ├── errors │ │ └── errors.go │ ├── example.bnf │ ├── example_test.go │ ├── gen.sh │ ├── lexer │ │ ├── acttab.go │ │ ├── lexer.go │ │ └── transitiontable.go │ ├── parser │ │ ├── action.go │ │ ├── actiontable.go │ │ ├── context.go │ │ ├── gototable.go │ │ ├── parser.go │ │ └── productionstable.go │ ├── token │ │ ├── context.go │ │ └── token.go │ └── util │ │ ├── litconv.go │ │ └── rune.go ├── calc │ ├── Makefile │ ├── calc.bnf │ ├── calc_test.go │ ├── doc.go │ ├── errors │ │ └── errors.go │ ├── lexer │ │ ├── acttab.go │ │ ├── lexer.go │ │ └── transitiontable.go │ ├── parser │ │ ├── action.go │ │ ├── actiontable.go │ │ ├── context.go │ │ ├── gototable.go │ │ ├── parser.go │ │ └── productionstable.go │ ├── token │ │ ├── context.go │ │ └── token.go │ └── util │ │ ├── litconv.go │ │ └── rune.go ├── errormsg │ ├── Makefile │ ├── errormsg_test.go │ ├── errors │ │ └── errors.go │ ├── example.bnf │ ├── lexer │ │ ├── acttab.go │ │ ├── lexer.go │ │ └── transitiontable.go │ ├── parser │ │ ├── action.go │ │ ├── actiontable.go │ │ ├── context.go │ │ ├── gototable.go │ │ ├── parser.go │ │ └── productionstable.go │ ├── token │ │ ├── context.go │ │ └── token.go │ └── util │ │ ├── litconv.go │ │ └── rune.go ├── errorrecovery │ ├── Makefile │ ├── ast │ │ └── ast.go │ ├── doc.go │ ├── er.bnf │ ├── er_test.go │ ├── errors │ │ └── errors.go │ ├── lexer │ │ ├── acttab.go │ │ ├── lexer.go │ │ └── transitiontable.go │ ├── parser │ │ ├── action.go │ │ ├── actiontable.go │ │ ├── context.go │ │ ├── gototable.go │ │ ├── parser.go │ │ ├── productionstable.go │ │ └── symbols.go │ ├── token │ │ ├── context.go │ │ └── token.go │ └── util │ │ ├── litconv.go │ │ └── rune.go ├── mail │ ├── Makefile │ ├── doc.go │ ├── lexer │ │ ├── acttab.go │ │ ├── lexer.go │ │ └── transitiontable.go │ ├── mail.bnf │ ├── parser_test.go │ ├── token │ │ ├── context.go │ │ └── token.go │ └── util │ │ ├── litconv.go │ │ └── rune.go ├── nolexer │ ├── Makefile │ ├── doc.go │ ├── errors │ │ └── errors.go │ ├── nolexer.bnf │ ├── nolexer_test.go │ ├── parser │ │ ├── action.go │ │ ├── actiontable.go │ │ ├── context.go │ │ ├── gototable.go │ │ ├── parser.go │ │ └── productionstable.go │ ├── scanner │ │ └── scanner.go │ ├── token │ │ ├── context.go │ │ └── token.go │ └── util │ │ ├── litconv.go │ │ └── rune.go ├── rr │ ├── Makefile │ ├── doc.go │ ├── errors │ │ └── errors.go │ ├── lexer │ │ ├── acttab.go │ │ ├── lexer.go │ │ └── transitiontable.go │ ├── parser │ │ ├── action.go │ │ ├── actiontable.go │ │ ├── context.go │ │ ├── gototable.go │ │ ├── parser.go │ │ └── productionstable.go │ ├── rr.bnf │ ├── rr_test.go │ ├── token │ │ ├── context.go │ │ └── token.go │ └── util │ │ ├── litconv.go │ │ └── rune.go ├── sr │ ├── Makefile │ ├── ast │ │ └── ast.go │ ├── doc.go │ ├── errors │ │ └── errors.go │ ├── lexer │ │ ├── acttab.go │ │ ├── lexer.go │ │ └── transitiontable.go │ ├── parser │ │ ├── action.go │ │ ├── actiontable.go │ │ ├── context.go │ │ ├── gototable.go │ │ ├── parser.go │ │ └── productionstable.go │ ├── sr.bnf │ ├── sr_test.go │ ├── token │ │ ├── context.go │ │ └── token.go │ └── util │ │ ├── litconv.go │ │ └── rune.go └── usercontext │ ├── Makefile │ ├── README.md │ ├── ast │ └── main.go │ ├── doc.go │ ├── errors │ └── errors.go │ ├── example.bnf │ ├── example_test.go │ ├── gen.sh │ ├── lexer │ ├── acttab.go │ ├── lexer.go │ └── transitiontable.go │ ├── parser │ ├── action.go │ ├── actiontable.go │ ├── context.go │ ├── gototable.go │ ├── parser.go │ └── productionstable.go │ ├── token │ ├── context.go │ └── token.go │ └── util │ ├── litconv.go │ └── rune.go ├── gen.sh ├── go.mod ├── go.sum ├── internal ├── ast │ ├── doc.go │ ├── fileheader.go │ ├── grammar.go │ ├── lexalt.go │ ├── lexcharlit.go │ ├── lexcharrange.go │ ├── lexdot.go │ ├── lexgrouppattern.go │ ├── lexignoredtokdef.go │ ├── leximport.go │ ├── leximports.go │ ├── lexnode.go │ ├── lexnodevisitor.go │ ├── lexnodewalker.go │ ├── lexntnode.go │ ├── lexoptpattern.go │ ├── lexpart.go │ ├── lexpattern.go │ ├── lexprodmap.go │ ├── lexproduction.go │ ├── lexproductions.go │ ├── lexregdef.go │ ├── lexregdefid.go │ ├── lexreppattern.go │ ├── lexterm.go │ ├── lextnode.go │ ├── lextokdef.go │ ├── syntaxalts.go │ ├── syntaxbody.go │ ├── syntaxempty.go │ ├── syntaxeof.go │ ├── syntaxerror.go │ ├── syntaxpart.go │ ├── syntaxprod.go │ ├── syntaxprodid.go │ ├── syntaxprodlist.go │ ├── syntaxstringlit.go │ ├── syntaxsymbol.go │ ├── syntaxsymbols.go │ └── syntaxtokid.go ├── config │ └── config.go ├── frontend │ ├── errors │ │ └── errors.go │ ├── parser │ │ ├── parser.go │ │ ├── parser_ut.go │ │ ├── tables.go │ │ └── tables_uncompressed.go │ ├── scanner │ │ ├── scanner.go │ │ └── scanner_test.go │ └── token │ │ ├── token.go │ │ └── tokens.go ├── io │ └── io.go ├── lexer │ ├── gen │ │ └── golang │ │ │ ├── acttab.go │ │ │ ├── asciitable.go │ │ │ ├── chrranges.go │ │ │ ├── gen.go │ │ │ ├── imports.go │ │ │ ├── lexer.go │ │ │ └── transtab.go │ ├── items │ │ ├── action.go │ │ ├── charrange.go │ │ ├── disjunctrangeset.go │ │ ├── disjunctrangeset_test.go │ │ ├── doc.go │ │ ├── item.go │ │ ├── item_test.go │ │ ├── itemlist.go │ │ ├── itempos.go │ │ ├── itempos_test.go │ │ ├── itemset.go │ │ ├── itemsets.go │ │ ├── itemsets_test.go │ │ └── testutils_test.go │ └── symbols │ │ ├── charlitsymbols.go │ │ ├── charrangesymbols.go │ │ └── symbols.go ├── parser │ ├── first │ │ ├── first.go │ │ └── symbolset.go │ ├── gen │ │ ├── gen.go │ │ └── golang │ │ │ ├── action.go │ │ │ ├── actiontable.go │ │ │ ├── context.go │ │ │ ├── errors.go │ │ │ ├── gototable.go │ │ │ ├── parser.go │ │ │ └── productionstable.go │ ├── lr1 │ │ ├── action │ │ │ └── action.go │ │ └── items │ │ │ ├── item.go │ │ │ ├── itemset.go │ │ │ ├── itemsets.go │ │ │ ├── rowconflicts.go │ │ │ └── testdata_test.go │ └── symbols │ │ └── symbols.go ├── test │ ├── Makefile │ ├── t1 │ │ ├── Makefile │ │ ├── doc.go │ │ ├── errors │ │ │ └── errors.go │ │ ├── lexer │ │ │ ├── acttab.go │ │ │ ├── lexer.go │ │ │ └── transitiontable.go │ │ ├── parser │ │ │ ├── action.go │ │ │ ├── actiontable.go │ │ │ ├── context.go │ │ │ ├── gototable.go │ │ │ ├── parser.go │ │ │ └── productionstable.go │ │ ├── t1.bnf │ │ ├── t1_test.go │ │ ├── terminals.txt │ │ ├── token │ │ │ ├── context.go │ │ │ └── token.go │ │ └── util │ │ │ ├── litconv.go │ │ │ └── rune.go │ └── t2 │ │ ├── t2.bnf │ │ └── t2_test.go ├── token │ ├── gen │ │ ├── gen.go │ │ └── golang │ │ │ ├── context.go │ │ │ └── token.go │ └── tokenmap.go └── util │ ├── gen │ ├── gen.go │ └── golang │ │ ├── litconv.go │ │ └── rune.go │ ├── litconv.go │ ├── md │ ├── Readme.md │ └── md.go │ ├── rune.go │ └── stack.go ├── main.go ├── spec └── gocc2.ebnf └── todo.txt /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_style = tab 3 | indent_size = 4 4 | trim_trailing_whitespace = true 5 | insert_final_newline = false 6 | end_of_line = lf 7 | 8 | [*.{go,bnf,tex}] 9 | charset = utf-8 10 | 11 | [{*.{yml,yaml}] 12 | indent_size = 2 13 | indent_style = space -------------------------------------------------------------------------------- /.errcheck-ignore: -------------------------------------------------------------------------------- 1 | fmt.Fprintf 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.go text eol=lf 2 | *.bnf text eol=lf 3 | *.md text eol=lf 4 | *.txt text eol=lf 5 | *.tex text eol=lf 6 | *.sh text eol=lf 7 | 8 | Makefile text eol=lf 9 | LICENSE text eol=lf 10 | 11 | *.pdf -text 12 | *.jpg -text 13 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | go: [1.24] 11 | env: 12 | working-directory: ./src/github.com/goccmack/gocc 13 | 14 | steps: 15 | - name: Set GOPATH 16 | run: | 17 | echo "GOPATH=$(dirname $GITHUB_WORKSPACE)/gocc" >> $GITHUB_ENV 18 | echo "$(dirname $GITHUB_WORKSPACE)/gocc/bin" >> $GITHUB_PATH 19 | shell: bash 20 | 21 | - name: Setup Go 22 | uses: actions/setup-go@v5 23 | with: 24 | go-version: ${{ matrix.go }} 25 | id: go 26 | 27 | - name: Checkout 28 | uses: actions/checkout@v4 29 | with: 30 | fetch-depth: 1 31 | path: src/github.com/goccmack/gocc 32 | 33 | - name: golangci-lint 34 | uses: golangci/golangci-lint-action@v7 35 | with: 36 | version: v2.1.2 37 | args: --issues-exit-code=0 # Do not care about output, we run golangci-lint in the Makefile again and then we do care. 38 | working-directory: ${{env.working-directory}} 39 | install-mode: "goinstall" # This is slow, but necessary if you are using a newer version of Go than golangci-lint supports 40 | 41 | - name: Check 42 | run: go get && make ci 43 | working-directory: ${{env.working-directory}} 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | gocc 2 | sm_* 3 | .vscode 4 | .vs 5 | .idea 6 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | linters: 3 | enable: 4 | - dogsled 5 | - dupl 6 | - gocyclo 7 | - misspell 8 | - prealloc 9 | - unconvert 10 | - whitespace 11 | disable: 12 | - depguard 13 | - govet 14 | - staticcheck 15 | - unused 16 | exclusions: 17 | generated: lax 18 | presets: 19 | - comments 20 | - common-false-positives 21 | - legacy 22 | - std-error-handling 23 | paths: 24 | - third_party$ 25 | - builtin$ 26 | - examples$ 27 | formatters: 28 | enable: 29 | - gofmt 30 | - goimports 31 | exclusions: 32 | generated: lax 33 | paths: 34 | - third_party$ 35 | - builtin$ 36 | - examples$ 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2012 Vastech SA (PTY) LTD 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test 2 | 3 | help: 4 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 5 | 6 | install: ## install the gocc binary 7 | go install . 8 | 9 | test: ## run all unit tests 10 | go test -v ./... 11 | 12 | gofmt: ## format all go files 13 | gofmt -l -s -w . 14 | 15 | govet: ## run go's code vetting on all code 16 | go vet ./... 17 | 18 | ci-lint: ## see https://golangci-lint.run/, applies .golangci.yml 19 | golangci-lint run 20 | 21 | lint: 22 | make govet 23 | make ci-lint 24 | 25 | goclean: gofmt ## apply go style rules to source 26 | 27 | regenerate: ## regenerate all example and test files 28 | make install 29 | make -C example regenerate 30 | make -C internal/test regenerate 31 | make goclean 32 | make lint 33 | 34 | check: ## regenerate, lint and run a terse version of check 35 | @# quietly install and regenerate 36 | @go mod tidy 37 | @make --quiet install 38 | @make --quiet -C example regenerate 39 | @make --quiet -C internal/test regenerate 40 | @# promote formatting changes to errors 41 | @if [ -n "$(gofmt -l -s .)" ]; then { echo "gofmt errors:"; gofmt -d -l -s . ; exit 1; }; fi 42 | @make --quiet lint 43 | @go test ./... | grep -v "\[no test" 44 | 45 | ci: ## run all ci checks 46 | make regenerate 47 | @git diff --exit-code . || { echo "ERROR: commit and working copy differ after 'make regenerate'"; exit 22 ; } 48 | make test 49 | @git diff --exit-code . || { echo "ERROR: commit and working copy differ after 'make test'" ; exit 22 ; } 50 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | *.aux 2 | *.log 3 | *.out 4 | *.toc -------------------------------------------------------------------------------- /doc/gocc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goccmack/gocc/42bd3d49df98af6e4fde05dd1329dbe2a2c2b4fb/doc/gocc.jpg -------------------------------------------------------------------------------- /doc/gocc_user_guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goccmack/gocc/42bd3d49df98af6e4fde05dd1329dbe2a2c2b4fb/doc/gocc_user_guide.pdf -------------------------------------------------------------------------------- /doc/hl_design.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goccmack/gocc/42bd3d49df98af6e4fde05dd1329dbe2a2c2b4fb/doc/hl_design.pdf -------------------------------------------------------------------------------- /doc/makedoc.sh: -------------------------------------------------------------------------------- 1 | pdflatex gocc_user_guide && pdflatex gocc_user_guide && pdflatex gocc_user_guide -------------------------------------------------------------------------------- /doc/target_grammar.tex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goccmack/gocc/42bd3d49df98af6e4fde05dd1329dbe2a2c2b4fb/doc/target_grammar.tex -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | sm_* -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | regenerate: 2 | make -C astx regenerate 3 | make -C bools regenerate 4 | make -C calc regenerate 5 | make -C errormsg regenerate 6 | make -C errorrecovery regenerate 7 | make -C mail regenerate 8 | make -C nolexer regenerate 9 | make -C rr regenerate 10 | make -C sr regenerate 11 | make -C usercontext regenerate 12 | -------------------------------------------------------------------------------- /example/astx/Makefile: -------------------------------------------------------------------------------- 1 | regenerate: 2 | gocc ast.bnf 3 | -------------------------------------------------------------------------------- /example/astx/ast.bnf: -------------------------------------------------------------------------------- 1 | /* Lexical elements */ 2 | 3 | _letter : 'a'-'z' | 'A'-'Z' ; 4 | 5 | _digit : '0'-'9' ; 6 | 7 | _idchar : _letter | _digit | '_' ; 8 | 9 | id : (_letter | '_') {_idchar} ; 10 | 11 | !whitespace : ' ' | '\t' | '\n' | '\r' ; 12 | 13 | /* Syntax elements */ 14 | 15 | << 16 | import ( 17 | "github.com/goccmack/gocc/example/astx/ast" 18 | "github.com/goccmack/gocc/example/astx/token" 19 | ) 20 | >> 21 | 22 | StmtList : 23 | Stmt << ast.NewStmtList($0) >> 24 | | StmtList Stmt << ast.AppendStmt($0, $1) >> 25 | ; 26 | 27 | Stmt : 28 | id << ast.NewStmt($T0) >> 29 | ; 30 | -------------------------------------------------------------------------------- /example/astx/ast/ast.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "github.com/goccmack/gocc/example/astx/token" 5 | ) 6 | 7 | type ( 8 | StmtList []Stmt 9 | Stmt string 10 | ) 11 | 12 | func NewStmtList(stmt interface{}) (StmtList, error) { 13 | return StmtList{stmt.(Stmt)}, nil 14 | } 15 | 16 | func AppendStmt(stmtList, stmt interface{}) (StmtList, error) { 17 | return append(stmtList.(StmtList), stmt.(Stmt)), nil 18 | } 19 | 20 | // stmtList is passed using $T0. 21 | func NewStmt(stmtList *token.Token) (Stmt, error) { 22 | return Stmt(stmtList.Lit), nil 23 | } 24 | -------------------------------------------------------------------------------- /example/astx/ast_test.go: -------------------------------------------------------------------------------- 1 | package astx 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/goccmack/gocc/example/astx/ast" 8 | "github.com/goccmack/gocc/example/astx/lexer" 9 | "github.com/goccmack/gocc/example/astx/parser" 10 | ) 11 | 12 | func TestPass(t *testing.T) { 13 | sml, err := test([]byte("a b c d e f")) 14 | if err != nil { 15 | t.Fatal(err.Error()) 16 | } 17 | fmt.Printf("output: %s\n", sml) 18 | } 19 | 20 | func TestFail(t *testing.T) { 21 | _, err := test([]byte("a b ; d e f")) 22 | if err == nil { 23 | t.Fatal("expected parse error") 24 | } else { 25 | fmt.Printf("Parsing failed as expected: %v\n", err) 26 | } 27 | } 28 | 29 | func test(src []byte) (astree ast.StmtList, err error) { 30 | fmt.Printf("input: %s\n", src) 31 | s := lexer.NewLexer(src) 32 | p := parser.NewParser() 33 | a, err := p.Parse(s) 34 | if err == nil { 35 | astree = a.(ast.StmtList) 36 | } 37 | return 38 | } 39 | -------------------------------------------------------------------------------- /example/astx/doc.go: -------------------------------------------------------------------------------- 1 | package astx 2 | -------------------------------------------------------------------------------- /example/astx/lexer/acttab.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package lexer 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/goccmack/gocc/example/astx/token" 9 | ) 10 | 11 | type ActionTable [NumStates]ActionRow 12 | 13 | type ActionRow struct { 14 | Accept token.Type 15 | Ignore string 16 | } 17 | 18 | func (a ActionRow) String() string { 19 | return fmt.Sprintf("Accept=%d, Ignore=%s", a.Accept, a.Ignore) 20 | } 21 | 22 | var ActTab = ActionTable{ 23 | ActionRow{ // S0 24 | Accept: 0, 25 | Ignore: "", 26 | }, 27 | ActionRow{ // S1 28 | Accept: -1, 29 | Ignore: "!whitespace", 30 | }, 31 | ActionRow{ // S2 32 | Accept: 2, 33 | Ignore: "", 34 | }, 35 | ActionRow{ // S3 36 | Accept: 2, 37 | Ignore: "", 38 | }, 39 | ActionRow{ // S4 40 | Accept: 2, 41 | Ignore: "", 42 | }, 43 | ActionRow{ // S5 44 | Accept: 2, 45 | Ignore: "", 46 | }, 47 | ActionRow{ // S6 48 | Accept: 2, 49 | Ignore: "", 50 | }, 51 | } 52 | -------------------------------------------------------------------------------- /example/astx/parser/action.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | type action interface { 10 | act() 11 | String() string 12 | } 13 | 14 | type ( 15 | accept bool 16 | shift int // value is next state index 17 | reduce int // value is production index 18 | ) 19 | 20 | func (this accept) act() {} 21 | func (this shift) act() {} 22 | func (this reduce) act() {} 23 | 24 | func (this accept) Equal(that action) bool { 25 | if _, ok := that.(accept); ok { 26 | return true 27 | } 28 | return false 29 | } 30 | 31 | func (this reduce) Equal(that action) bool { 32 | that1, ok := that.(reduce) 33 | if !ok { 34 | return false 35 | } 36 | return this == that1 37 | } 38 | 39 | func (this shift) Equal(that action) bool { 40 | that1, ok := that.(shift) 41 | if !ok { 42 | return false 43 | } 44 | return this == that1 45 | } 46 | 47 | func (this accept) String() string { return "accept(0)" } 48 | func (this shift) String() string { return fmt.Sprintf("shift:%d", this) } 49 | func (this reduce) String() string { 50 | return fmt.Sprintf("reduce:%d(%s)", this, productionsTable[this].String) 51 | } 52 | -------------------------------------------------------------------------------- /example/astx/parser/actiontable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | type ( 6 | actionTable [numStates]actionRow 7 | actionRow struct { 8 | canRecover bool 9 | actions [numSymbols]action 10 | } 11 | ) 12 | 13 | var actionTab = actionTable{ 14 | actionRow{ // S0 15 | canRecover: false, 16 | actions: [numSymbols]action{ 17 | nil, // INVALID 18 | nil, // ␚ 19 | shift(3), // id 20 | }, 21 | }, 22 | actionRow{ // S1 23 | canRecover: false, 24 | actions: [numSymbols]action{ 25 | nil, // INVALID 26 | accept(true), // ␚ 27 | shift(3), // id 28 | }, 29 | }, 30 | actionRow{ // S2 31 | canRecover: false, 32 | actions: [numSymbols]action{ 33 | nil, // INVALID 34 | reduce(1), // ␚, reduce: StmtList 35 | reduce(1), // id, reduce: StmtList 36 | }, 37 | }, 38 | actionRow{ // S3 39 | canRecover: false, 40 | actions: [numSymbols]action{ 41 | nil, // INVALID 42 | reduce(3), // ␚, reduce: Stmt 43 | reduce(3), // id, reduce: Stmt 44 | }, 45 | }, 46 | actionRow{ // S4 47 | canRecover: false, 48 | actions: [numSymbols]action{ 49 | nil, // INVALID 50 | reduce(2), // ␚, reduce: StmtList 51 | reduce(2), // id, reduce: StmtList 52 | }, 53 | }, 54 | } 55 | -------------------------------------------------------------------------------- /example/astx/parser/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | // Parser-specific user-defined and entirely-optional context, 6 | // accessible as '$Context' in SDT actions. 7 | type Context interface{} 8 | -------------------------------------------------------------------------------- /example/astx/parser/gototable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | const numNTSymbols = 3 6 | 7 | type ( 8 | gotoTable [numStates]gotoRow 9 | gotoRow [numNTSymbols]int 10 | ) 11 | 12 | var gotoTab = gotoTable{ 13 | gotoRow{ // S0 14 | -1, // S' 15 | 1, // StmtList 16 | 2, // Stmt 17 | }, 18 | gotoRow{ // S1 19 | -1, // S' 20 | -1, // StmtList 21 | 4, // Stmt 22 | }, 23 | gotoRow{ // S2 24 | -1, // S' 25 | -1, // StmtList 26 | -1, // Stmt 27 | }, 28 | gotoRow{ // S3 29 | -1, // S' 30 | -1, // StmtList 31 | -1, // Stmt 32 | }, 33 | gotoRow{ // S4 34 | -1, // S' 35 | -1, // StmtList 36 | -1, // Stmt 37 | }, 38 | } 39 | -------------------------------------------------------------------------------- /example/astx/parser/productionstable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import ( 6 | "github.com/goccmack/gocc/example/astx/ast" 7 | "github.com/goccmack/gocc/example/astx/token" 8 | ) 9 | 10 | type ( 11 | ProdTab [numProductions]ProdTabEntry 12 | ProdTabEntry struct { 13 | String string 14 | Id string 15 | NTType int 16 | Index int 17 | NumSymbols int 18 | ReduceFunc func([]Attrib, interface{}) (Attrib, error) 19 | } 20 | Attrib interface { 21 | } 22 | ) 23 | 24 | var productionsTable = ProdTab{ 25 | ProdTabEntry{ 26 | String: `S' : StmtList << >>`, 27 | Id: "S'", 28 | NTType: 0, 29 | Index: 0, 30 | NumSymbols: 1, 31 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 32 | return X[0], nil 33 | }, 34 | }, 35 | ProdTabEntry{ 36 | String: `StmtList : Stmt << ast.NewStmtList(X[0]) >>`, 37 | Id: "StmtList", 38 | NTType: 1, 39 | Index: 1, 40 | NumSymbols: 1, 41 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 42 | return ast.NewStmtList(X[0]) 43 | }, 44 | }, 45 | ProdTabEntry{ 46 | String: `StmtList : StmtList Stmt << ast.AppendStmt(X[0], X[1]) >>`, 47 | Id: "StmtList", 48 | NTType: 1, 49 | Index: 2, 50 | NumSymbols: 2, 51 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 52 | return ast.AppendStmt(X[0], X[1]) 53 | }, 54 | }, 55 | ProdTabEntry{ 56 | String: `Stmt : id << ast.NewStmt(X[0].(*token.Token)) >>`, 57 | Id: "Stmt", 58 | NTType: 2, 59 | Index: 3, 60 | NumSymbols: 1, 61 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 62 | return ast.NewStmt(X[0].(*token.Token)) 63 | }, 64 | }, 65 | } 66 | -------------------------------------------------------------------------------- /example/astx/token/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package token 4 | 5 | // Context allows user-defined data to be associated with the 6 | // lexer/scanner to be associated with each token that lexer 7 | // produces. 8 | type Context interface{} 9 | 10 | // Sourcer is a Context interface which presents a Source() method 11 | // identifying e.g the filename for the current code. 12 | type Sourcer interface { 13 | Source() string 14 | } 15 | -------------------------------------------------------------------------------- /example/astx/util/rune.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package util 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | func RuneToString(r rune) string { 10 | if r >= 0x20 && r < 0x7f { 11 | return fmt.Sprintf("'%c'", r) 12 | } 13 | switch r { 14 | case 0x07: 15 | return "'\\a'" 16 | case 0x08: 17 | return "'\\b'" 18 | case 0x0C: 19 | return "'\\f'" 20 | case 0x0A: 21 | return "'\\n'" 22 | case 0x0D: 23 | return "'\\r'" 24 | case 0x09: 25 | return "'\\t'" 26 | case 0x0b: 27 | return "'\\v'" 28 | case 0x5c: 29 | return "'\\\\\\'" 30 | case 0x27: 31 | return "'\\''" 32 | case 0x22: 33 | return "'\\\"'" 34 | } 35 | if r < 0x10000 { 36 | return fmt.Sprintf("\\u%04x", r) 37 | } 38 | return fmt.Sprintf("\\U%08x", r) 39 | } 40 | -------------------------------------------------------------------------------- /example/bools/Makefile: -------------------------------------------------------------------------------- 1 | regenerate: 2 | gocc -a example.bnf 3 | -------------------------------------------------------------------------------- /example/bools/README: -------------------------------------------------------------------------------- 1 | Generating a parser starts with creating a bnf file. 2 | We have created an example.bnf file to illustrate this. 3 | Running gen.sh will generate the parser, scanner and token code 4 | needed to parse the language. 5 | 6 | The ast (abstract syntax tree) package needs to created by the user. 7 | This package should contain the corresponding function calls 8 | required by the syntax directed translation rules. 9 | See the example/ast package we have created. 10 | 11 | Parsing a string with the generated code and evaluating the ast is 12 | shown in example/example_test.go with some corresponding tests. 13 | -------------------------------------------------------------------------------- /example/bools/doc.go: -------------------------------------------------------------------------------- 1 | package example 2 | -------------------------------------------------------------------------------- /example/bools/example.bnf: -------------------------------------------------------------------------------- 1 | //Copyright 2012 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | int_lit : _digit {_digit} ; 16 | 17 | _digit : '0'-'9' ; 18 | 19 | string_lit : '"' {.} '"' ; 20 | 21 | !whitespace : ' ' | '\t' | '\n' | '\r' ; 22 | 23 | <> 24 | 25 | BoolExpr 26 | : BoolExpr1 << $0, nil >> 27 | ; 28 | 29 | BoolExpr1 30 | : Val << $0, nil >> 31 | | BoolExpr "&" BoolExpr1 << ast.NewBoolAndExpr($0, $2) >> 32 | | BoolExpr "|" BoolExpr1 << ast.NewBoolOrExpr($0, $2) >> 33 | | "(" BoolExpr ")" << ast.NewBoolGroupExpr($1) >> 34 | ; 35 | 36 | Val 37 | : "true" << ast.TRUE, nil >> 38 | | "false" << ast.FALSE, nil >> 39 | | CompareExpr << $0, nil >> 40 | | SubStringExpr << $0, nil >> 41 | ; 42 | 43 | CompareExpr 44 | : int_lit "<" int_lit << ast.NewLessThanExpr($0, $2) >> 45 | | int_lit ">" int_lit << ast.NewLessThanExpr($2, $0) >> 46 | ; 47 | 48 | SubStringExpr 49 | : string_lit "in" string_lit << ast.NewSubStringExpr($0, $2) >> 50 | ; 51 | -------------------------------------------------------------------------------- /example/bools/example_test.go: -------------------------------------------------------------------------------- 1 | //Copyright 2012 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package example 16 | 17 | import ( 18 | "testing" 19 | 20 | "github.com/goccmack/gocc/example/bools/ast" 21 | "github.com/goccmack/gocc/example/bools/lexer" 22 | "github.com/goccmack/gocc/example/bools/parser" 23 | ) 24 | 25 | func testEval(t *testing.T, exampleStr string, output bool) { 26 | lex := lexer.NewLexer([]byte(exampleStr)) 27 | p := parser.NewParser() 28 | st, err := p.Parse(lex) 29 | if err != nil { 30 | panic(err) 31 | } 32 | if st.(ast.Val).Eval() != output { 33 | t.Fatalf("Should be %v for %v", output, exampleStr) 34 | } 35 | } 36 | 37 | func TestOr(t *testing.T) { 38 | testEval(t, "true | false", true) 39 | } 40 | 41 | func TestAnd(t *testing.T) { 42 | testEval(t, "true & false", false) 43 | } 44 | 45 | func TestSubString(t *testing.T) { 46 | testEval(t, `"true" in "false"`, false) 47 | testEval(t, `"true" in "trues"`, true) 48 | } 49 | 50 | func TestLess(t *testing.T) { 51 | testEval(t, "0 < 5", true) 52 | testEval(t, "0 > 5", false) 53 | } 54 | 55 | func TestMixed(t *testing.T) { 56 | testEval(t, "0 < 5 | false", true) 57 | } 58 | 59 | func TestGroup(t *testing.T) { 60 | testEval(t, "( true | false ) & ( true & true )", true) 61 | } 62 | 63 | func TestGroupMixed(t *testing.T) { 64 | testEval(t, `( true | false ) & 0 > 100000 | "t" in "taddle"`, true) 65 | } 66 | -------------------------------------------------------------------------------- /example/bools/gen.sh: -------------------------------------------------------------------------------- 1 | gocc -a example.bnf 2 | -------------------------------------------------------------------------------- /example/bools/lexer/acttab.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package lexer 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/goccmack/gocc/example/bools/token" 9 | ) 10 | 11 | type ActionTable [NumStates]ActionRow 12 | 13 | type ActionRow struct { 14 | Accept token.Type 15 | Ignore string 16 | } 17 | 18 | func (a ActionRow) String() string { 19 | return fmt.Sprintf("Accept=%d, Ignore=%s", a.Accept, a.Ignore) 20 | } 21 | 22 | var ActTab = ActionTable{ 23 | ActionRow{ // S0 24 | Accept: 0, 25 | Ignore: "", 26 | }, 27 | ActionRow{ // S1 28 | Accept: -1, 29 | Ignore: "!whitespace", 30 | }, 31 | ActionRow{ // S2 32 | Accept: 0, 33 | Ignore: "", 34 | }, 35 | ActionRow{ // S3 36 | Accept: 2, 37 | Ignore: "", 38 | }, 39 | ActionRow{ // S4 40 | Accept: 4, 41 | Ignore: "", 42 | }, 43 | ActionRow{ // S5 44 | Accept: 5, 45 | Ignore: "", 46 | }, 47 | ActionRow{ // S6 48 | Accept: 8, 49 | Ignore: "", 50 | }, 51 | ActionRow{ // S7 52 | Accept: 9, 53 | Ignore: "", 54 | }, 55 | ActionRow{ // S8 56 | Accept: 10, 57 | Ignore: "", 58 | }, 59 | ActionRow{ // S9 60 | Accept: 0, 61 | Ignore: "", 62 | }, 63 | ActionRow{ // S10 64 | Accept: 0, 65 | Ignore: "", 66 | }, 67 | ActionRow{ // S11 68 | Accept: 0, 69 | Ignore: "", 70 | }, 71 | ActionRow{ // S12 72 | Accept: 3, 73 | Ignore: "", 74 | }, 75 | ActionRow{ // S13 76 | Accept: 11, 77 | Ignore: "", 78 | }, 79 | ActionRow{ // S14 80 | Accept: 0, 81 | Ignore: "", 82 | }, 83 | ActionRow{ // S15 84 | Accept: 12, 85 | Ignore: "", 86 | }, 87 | ActionRow{ // S16 88 | Accept: 0, 89 | Ignore: "", 90 | }, 91 | ActionRow{ // S17 92 | Accept: 0, 93 | Ignore: "", 94 | }, 95 | ActionRow{ // S18 96 | Accept: 0, 97 | Ignore: "", 98 | }, 99 | ActionRow{ // S19 100 | Accept: 0, 101 | Ignore: "", 102 | }, 103 | ActionRow{ // S20 104 | Accept: 6, 105 | Ignore: "", 106 | }, 107 | ActionRow{ // S21 108 | Accept: 7, 109 | Ignore: "", 110 | }, 111 | } 112 | -------------------------------------------------------------------------------- /example/bools/parser/action.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | type action interface { 10 | act() 11 | String() string 12 | } 13 | 14 | type ( 15 | accept bool 16 | shift int // value is next state index 17 | reduce int // value is production index 18 | ) 19 | 20 | func (this accept) act() {} 21 | func (this shift) act() {} 22 | func (this reduce) act() {} 23 | 24 | func (this accept) Equal(that action) bool { 25 | if _, ok := that.(accept); ok { 26 | return true 27 | } 28 | return false 29 | } 30 | 31 | func (this reduce) Equal(that action) bool { 32 | that1, ok := that.(reduce) 33 | if !ok { 34 | return false 35 | } 36 | return this == that1 37 | } 38 | 39 | func (this shift) Equal(that action) bool { 40 | that1, ok := that.(shift) 41 | if !ok { 42 | return false 43 | } 44 | return this == that1 45 | } 46 | 47 | func (this accept) String() string { return "accept(0)" } 48 | func (this shift) String() string { return fmt.Sprintf("shift:%d", this) } 49 | func (this reduce) String() string { 50 | return fmt.Sprintf("reduce:%d(%s)", this, productionsTable[this].String) 51 | } 52 | -------------------------------------------------------------------------------- /example/bools/parser/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | // Parser-specific user-defined and entirely-optional context, 6 | // accessible as '$Context' in SDT actions. 7 | type Context interface{} 8 | -------------------------------------------------------------------------------- /example/bools/token/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package token 4 | 5 | // Context allows user-defined data to be associated with the 6 | // lexer/scanner to be associated with each token that lexer 7 | // produces. 8 | type Context interface{} 9 | 10 | // Sourcer is a Context interface which presents a Source() method 11 | // identifying e.g the filename for the current code. 12 | type Sourcer interface { 13 | Source() string 14 | } 15 | -------------------------------------------------------------------------------- /example/bools/util/rune.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package util 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | func RuneToString(r rune) string { 10 | if r >= 0x20 && r < 0x7f { 11 | return fmt.Sprintf("'%c'", r) 12 | } 13 | switch r { 14 | case 0x07: 15 | return "'\\a'" 16 | case 0x08: 17 | return "'\\b'" 18 | case 0x0C: 19 | return "'\\f'" 20 | case 0x0A: 21 | return "'\\n'" 22 | case 0x0D: 23 | return "'\\r'" 24 | case 0x09: 25 | return "'\\t'" 26 | case 0x0b: 27 | return "'\\v'" 28 | case 0x5c: 29 | return "'\\\\\\'" 30 | case 0x27: 31 | return "'\\''" 32 | case 0x22: 33 | return "'\\\"'" 34 | } 35 | if r < 0x10000 { 36 | return fmt.Sprintf("\\u%04x", r) 37 | } 38 | return fmt.Sprintf("\\U%08x", r) 39 | } 40 | -------------------------------------------------------------------------------- /example/calc/Makefile: -------------------------------------------------------------------------------- 1 | regenerate: 2 | gocc calc.bnf 3 | -------------------------------------------------------------------------------- /example/calc/calc.bnf: -------------------------------------------------------------------------------- 1 | /* Lexical part */ 2 | 3 | _digit : '0'-'9' ; 4 | 5 | int64 : '1'-'9' {_digit} ; 6 | 7 | !whitespace : ' ' | '\t' | '\n' | '\r' ; 8 | 9 | /* Syntax part */ 10 | 11 | << 12 | import ( 13 | "github.com/goccmack/gocc/example/calc/token" 14 | "github.com/goccmack/gocc/example/calc/util" 15 | ) 16 | >> 17 | 18 | Calc : Expr; 19 | 20 | Expr : 21 | Expr "+" Term << $0.(int64) + $2.(int64), nil >> 22 | | Term 23 | ; 24 | 25 | Term : 26 | Term "*" Factor << $0.(int64) * $2.(int64), nil >> 27 | | Factor 28 | ; 29 | 30 | Factor : 31 | "(" Expr ")" << $1, nil >> 32 | | int64 << util.IntValue($0.(*token.Token).Lit) >> 33 | ; 34 | -------------------------------------------------------------------------------- /example/calc/calc_test.go: -------------------------------------------------------------------------------- 1 | package calc 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/goccmack/gocc/example/calc/lexer" 7 | "github.com/goccmack/gocc/example/calc/parser" 8 | ) 9 | 10 | type TI struct { 11 | src string 12 | expect int64 13 | } 14 | 15 | var testData = []*TI{ 16 | {"1 + 1", 2}, 17 | {"1 * 1", 1}, 18 | {"1 + 2 * 3", 7}, 19 | } 20 | 21 | func Test1(t *testing.T) { 22 | p := parser.NewParser() 23 | for _, ts := range testData { 24 | s := lexer.NewLexer([]byte(ts.src)) 25 | sum, err := p.Parse(s) 26 | if err != nil { 27 | t.Error(err) 28 | } 29 | if sum != ts.expect { 30 | t.Errorf("Error: %s = %d. Expected %d\n", ts.src, sum, ts.expect) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /example/calc/doc.go: -------------------------------------------------------------------------------- 1 | package calc 2 | -------------------------------------------------------------------------------- /example/calc/lexer/acttab.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package lexer 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/goccmack/gocc/example/calc/token" 9 | ) 10 | 11 | type ActionTable [NumStates]ActionRow 12 | 13 | type ActionRow struct { 14 | Accept token.Type 15 | Ignore string 16 | } 17 | 18 | func (a ActionRow) String() string { 19 | return fmt.Sprintf("Accept=%d, Ignore=%s", a.Accept, a.Ignore) 20 | } 21 | 22 | var ActTab = ActionTable{ 23 | ActionRow{ // S0 24 | Accept: 0, 25 | Ignore: "", 26 | }, 27 | ActionRow{ // S1 28 | Accept: -1, 29 | Ignore: "!whitespace", 30 | }, 31 | ActionRow{ // S2 32 | Accept: 4, 33 | Ignore: "", 34 | }, 35 | ActionRow{ // S3 36 | Accept: 5, 37 | Ignore: "", 38 | }, 39 | ActionRow{ // S4 40 | Accept: 3, 41 | Ignore: "", 42 | }, 43 | ActionRow{ // S5 44 | Accept: 2, 45 | Ignore: "", 46 | }, 47 | ActionRow{ // S6 48 | Accept: 6, 49 | Ignore: "", 50 | }, 51 | ActionRow{ // S7 52 | Accept: 6, 53 | Ignore: "", 54 | }, 55 | } 56 | -------------------------------------------------------------------------------- /example/calc/lexer/transitiontable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package lexer 4 | 5 | /* 6 | Let s be the current state 7 | Let r be the current input rune 8 | transitionTable[s](r) returns the next state. 9 | */ 10 | type TransitionTable [NumStates]func(rune) int 11 | 12 | var TransTab = TransitionTable{ 13 | // S0 14 | func(r rune) int { 15 | switch { 16 | case r == 9: // ['\t','\t'] 17 | return 1 18 | case r == 10: // ['\n','\n'] 19 | return 1 20 | case r == 13: // ['\r','\r'] 21 | return 1 22 | case r == 32: // [' ',' '] 23 | return 1 24 | case r == 40: // ['(','('] 25 | return 2 26 | case r == 41: // [')',')'] 27 | return 3 28 | case r == 42: // ['*','*'] 29 | return 4 30 | case r == 43: // ['+','+'] 31 | return 5 32 | case 49 <= r && r <= 57: // ['1','9'] 33 | return 6 34 | } 35 | return NoState 36 | }, 37 | // S1 38 | func(r rune) int { 39 | switch { 40 | } 41 | return NoState 42 | }, 43 | // S2 44 | func(r rune) int { 45 | switch { 46 | } 47 | return NoState 48 | }, 49 | // S3 50 | func(r rune) int { 51 | switch { 52 | } 53 | return NoState 54 | }, 55 | // S4 56 | func(r rune) int { 57 | switch { 58 | } 59 | return NoState 60 | }, 61 | // S5 62 | func(r rune) int { 63 | switch { 64 | } 65 | return NoState 66 | }, 67 | // S6 68 | func(r rune) int { 69 | switch { 70 | case 48 <= r && r <= 57: // ['0','9'] 71 | return 7 72 | } 73 | return NoState 74 | }, 75 | // S7 76 | func(r rune) int { 77 | switch { 78 | case 48 <= r && r <= 57: // ['0','9'] 79 | return 7 80 | } 81 | return NoState 82 | }, 83 | } 84 | -------------------------------------------------------------------------------- /example/calc/parser/action.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | type action interface { 10 | act() 11 | String() string 12 | } 13 | 14 | type ( 15 | accept bool 16 | shift int // value is next state index 17 | reduce int // value is production index 18 | ) 19 | 20 | func (this accept) act() {} 21 | func (this shift) act() {} 22 | func (this reduce) act() {} 23 | 24 | func (this accept) Equal(that action) bool { 25 | if _, ok := that.(accept); ok { 26 | return true 27 | } 28 | return false 29 | } 30 | 31 | func (this reduce) Equal(that action) bool { 32 | that1, ok := that.(reduce) 33 | if !ok { 34 | return false 35 | } 36 | return this == that1 37 | } 38 | 39 | func (this shift) Equal(that action) bool { 40 | that1, ok := that.(shift) 41 | if !ok { 42 | return false 43 | } 44 | return this == that1 45 | } 46 | 47 | func (this accept) String() string { return "accept(0)" } 48 | func (this shift) String() string { return fmt.Sprintf("shift:%d", this) } 49 | func (this reduce) String() string { 50 | return fmt.Sprintf("reduce:%d(%s)", this, productionsTable[this].String) 51 | } 52 | -------------------------------------------------------------------------------- /example/calc/parser/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | // Parser-specific user-defined and entirely-optional context, 6 | // accessible as '$Context' in SDT actions. 7 | type Context interface{} 8 | -------------------------------------------------------------------------------- /example/calc/token/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package token 4 | 5 | // Context allows user-defined data to be associated with the 6 | // lexer/scanner to be associated with each token that lexer 7 | // produces. 8 | type Context interface{} 9 | 10 | // Sourcer is a Context interface which presents a Source() method 11 | // identifying e.g the filename for the current code. 12 | type Sourcer interface { 13 | Source() string 14 | } 15 | -------------------------------------------------------------------------------- /example/calc/util/rune.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package util 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | func RuneToString(r rune) string { 10 | if r >= 0x20 && r < 0x7f { 11 | return fmt.Sprintf("'%c'", r) 12 | } 13 | switch r { 14 | case 0x07: 15 | return "'\\a'" 16 | case 0x08: 17 | return "'\\b'" 18 | case 0x0C: 19 | return "'\\f'" 20 | case 0x0A: 21 | return "'\\n'" 22 | case 0x0D: 23 | return "'\\r'" 24 | case 0x09: 25 | return "'\\t'" 26 | case 0x0b: 27 | return "'\\v'" 28 | case 0x5c: 29 | return "'\\\\\\'" 30 | case 0x27: 31 | return "'\\''" 32 | case 0x22: 33 | return "'\\\"'" 34 | } 35 | if r < 0x10000 { 36 | return fmt.Sprintf("\\u%04x", r) 37 | } 38 | return fmt.Sprintf("\\U%08x", r) 39 | } 40 | -------------------------------------------------------------------------------- /example/errormsg/Makefile: -------------------------------------------------------------------------------- 1 | regenerate: 2 | gocc example.bnf 3 | -------------------------------------------------------------------------------- /example/errormsg/example.bnf: -------------------------------------------------------------------------------- 1 | // Simple grammar that provides has increasing number of options for each 2 | // position in its declaration type. The first token has to be "var", 3 | // the second can be an idetifier or "_', the third could be "=", ":=" or 4 | // ";", and so on. 5 | 6 | !_whitespace : ' ' ; 7 | 8 | _letter : 'a'-'z' | 'A'-'Z' | '_' ; 9 | _digit : '0'-'9' ; 10 | 11 | identifier : _letter { _letter } ; 12 | 13 | float : _digit { _digit } '.' { _digit } ; 14 | integer : _digit { _digit } ; 15 | 16 | 17 | Declaration 18 | : "var" Name Equal Default ";" 19 | | "var" Name ";" 20 | ; 21 | 22 | 23 | Name 24 | : identifier 25 | | "_" 26 | ; 27 | 28 | Equal 29 | : "=" | ":=" 30 | ; 31 | 32 | Default 33 | : identifier | "_" | float | integer 34 | ; 35 | 36 | -------------------------------------------------------------------------------- /example/errormsg/lexer/acttab.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package lexer 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/goccmack/gocc/example/errormsg/token" 9 | ) 10 | 11 | type ActionTable [NumStates]ActionRow 12 | 13 | type ActionRow struct { 14 | Accept token.Type 15 | Ignore string 16 | } 17 | 18 | func (a ActionRow) String() string { 19 | return fmt.Sprintf("Accept=%d, Ignore=%s", a.Accept, a.Ignore) 20 | } 21 | 22 | var ActTab = ActionTable{ 23 | ActionRow{ // S0 24 | Accept: 0, 25 | Ignore: "", 26 | }, 27 | ActionRow{ // S1 28 | Accept: -1, 29 | Ignore: "!_whitespace", 30 | }, 31 | ActionRow{ // S2 32 | Accept: 9, 33 | Ignore: "", 34 | }, 35 | ActionRow{ // S3 36 | Accept: 0, 37 | Ignore: "", 38 | }, 39 | ActionRow{ // S4 40 | Accept: 3, 41 | Ignore: "", 42 | }, 43 | ActionRow{ // S5 44 | Accept: 6, 45 | Ignore: "", 46 | }, 47 | ActionRow{ // S6 48 | Accept: 4, 49 | Ignore: "", 50 | }, 51 | ActionRow{ // S7 52 | Accept: 5, 53 | Ignore: "", 54 | }, 55 | ActionRow{ // S8 56 | Accept: 4, 57 | Ignore: "", 58 | }, 59 | ActionRow{ // S9 60 | Accept: 8, 61 | Ignore: "", 62 | }, 63 | ActionRow{ // S10 64 | Accept: 7, 65 | Ignore: "", 66 | }, 67 | ActionRow{ // S11 68 | Accept: 4, 69 | Ignore: "", 70 | }, 71 | ActionRow{ // S12 72 | Accept: 8, 73 | Ignore: "", 74 | }, 75 | ActionRow{ // S13 76 | Accept: 2, 77 | Ignore: "", 78 | }, 79 | } 80 | -------------------------------------------------------------------------------- /example/errormsg/parser/action.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | type action interface { 10 | act() 11 | String() string 12 | } 13 | 14 | type ( 15 | accept bool 16 | shift int // value is next state index 17 | reduce int // value is production index 18 | ) 19 | 20 | func (this accept) act() {} 21 | func (this shift) act() {} 22 | func (this reduce) act() {} 23 | 24 | func (this accept) Equal(that action) bool { 25 | if _, ok := that.(accept); ok { 26 | return true 27 | } 28 | return false 29 | } 30 | 31 | func (this reduce) Equal(that action) bool { 32 | that1, ok := that.(reduce) 33 | if !ok { 34 | return false 35 | } 36 | return this == that1 37 | } 38 | 39 | func (this shift) Equal(that action) bool { 40 | that1, ok := that.(shift) 41 | if !ok { 42 | return false 43 | } 44 | return this == that1 45 | } 46 | 47 | func (this accept) String() string { return "accept(0)" } 48 | func (this shift) String() string { return fmt.Sprintf("shift:%d", this) } 49 | func (this reduce) String() string { 50 | return fmt.Sprintf("reduce:%d(%s)", this, productionsTable[this].String) 51 | } 52 | -------------------------------------------------------------------------------- /example/errormsg/parser/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | // Parser-specific user-defined and entirely-optional context, 6 | // accessible as '$Context' in SDT actions. 7 | type Context interface{} 8 | -------------------------------------------------------------------------------- /example/errormsg/parser/gototable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | const numNTSymbols = 5 6 | 7 | type ( 8 | gotoTable [numStates]gotoRow 9 | gotoRow [numNTSymbols]int 10 | ) 11 | 12 | var gotoTab = gotoTable{ 13 | gotoRow{ // S0 14 | -1, // S' 15 | 1, // Declaration 16 | -1, // Name 17 | -1, // Equal 18 | -1, // Default 19 | }, 20 | gotoRow{ // S1 21 | -1, // S' 22 | -1, // Declaration 23 | -1, // Name 24 | -1, // Equal 25 | -1, // Default 26 | }, 27 | gotoRow{ // S2 28 | -1, // S' 29 | -1, // Declaration 30 | 3, // Name 31 | -1, // Equal 32 | -1, // Default 33 | }, 34 | gotoRow{ // S3 35 | -1, // S' 36 | -1, // Declaration 37 | -1, // Name 38 | 6, // Equal 39 | -1, // Default 40 | }, 41 | gotoRow{ // S4 42 | -1, // S' 43 | -1, // Declaration 44 | -1, // Name 45 | -1, // Equal 46 | -1, // Default 47 | }, 48 | gotoRow{ // S5 49 | -1, // S' 50 | -1, // Declaration 51 | -1, // Name 52 | -1, // Equal 53 | -1, // Default 54 | }, 55 | gotoRow{ // S6 56 | -1, // S' 57 | -1, // Declaration 58 | -1, // Name 59 | -1, // Equal 60 | 10, // Default 61 | }, 62 | gotoRow{ // S7 63 | -1, // S' 64 | -1, // Declaration 65 | -1, // Name 66 | -1, // Equal 67 | -1, // Default 68 | }, 69 | gotoRow{ // S8 70 | -1, // S' 71 | -1, // Declaration 72 | -1, // Name 73 | -1, // Equal 74 | -1, // Default 75 | }, 76 | gotoRow{ // S9 77 | -1, // S' 78 | -1, // Declaration 79 | -1, // Name 80 | -1, // Equal 81 | -1, // Default 82 | }, 83 | gotoRow{ // S10 84 | -1, // S' 85 | -1, // Declaration 86 | -1, // Name 87 | -1, // Equal 88 | -1, // Default 89 | }, 90 | gotoRow{ // S11 91 | -1, // S' 92 | -1, // Declaration 93 | -1, // Name 94 | -1, // Equal 95 | -1, // Default 96 | }, 97 | gotoRow{ // S12 98 | -1, // S' 99 | -1, // Declaration 100 | -1, // Name 101 | -1, // Equal 102 | -1, // Default 103 | }, 104 | gotoRow{ // S13 105 | -1, // S' 106 | -1, // Declaration 107 | -1, // Name 108 | -1, // Equal 109 | -1, // Default 110 | }, 111 | gotoRow{ // S14 112 | -1, // S' 113 | -1, // Declaration 114 | -1, // Name 115 | -1, // Equal 116 | -1, // Default 117 | }, 118 | gotoRow{ // S15 119 | -1, // S' 120 | -1, // Declaration 121 | -1, // Name 122 | -1, // Equal 123 | -1, // Default 124 | }, 125 | } 126 | -------------------------------------------------------------------------------- /example/errormsg/token/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package token 4 | 5 | // Context allows user-defined data to be associated with the 6 | // lexer/scanner to be associated with each token that lexer 7 | // produces. 8 | type Context interface{} 9 | 10 | // Sourcer is a Context interface which presents a Source() method 11 | // identifying e.g the filename for the current code. 12 | type Sourcer interface { 13 | Source() string 14 | } 15 | -------------------------------------------------------------------------------- /example/errormsg/util/rune.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package util 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | func RuneToString(r rune) string { 10 | if r >= 0x20 && r < 0x7f { 11 | return fmt.Sprintf("'%c'", r) 12 | } 13 | switch r { 14 | case 0x07: 15 | return "'\\a'" 16 | case 0x08: 17 | return "'\\b'" 18 | case 0x0C: 19 | return "'\\f'" 20 | case 0x0A: 21 | return "'\\n'" 22 | case 0x0D: 23 | return "'\\r'" 24 | case 0x09: 25 | return "'\\t'" 26 | case 0x0b: 27 | return "'\\v'" 28 | case 0x5c: 29 | return "'\\\\\\'" 30 | case 0x27: 31 | return "'\\''" 32 | case 0x22: 33 | return "'\\\"'" 34 | } 35 | if r < 0x10000 { 36 | return fmt.Sprintf("\\u%04x", r) 37 | } 38 | return fmt.Sprintf("\\U%08x", r) 39 | } 40 | -------------------------------------------------------------------------------- /example/errorrecovery/Makefile: -------------------------------------------------------------------------------- 1 | regenerate: 2 | gocc er.bnf 3 | -------------------------------------------------------------------------------- /example/errorrecovery/ast/ast.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "github.com/goccmack/gocc/example/errorrecovery/token" 5 | ) 6 | 7 | type ( 8 | StmtList []interface{} 9 | Stmt string 10 | ) 11 | 12 | func NewStmtList(stmt interface{}) (StmtList, error) { 13 | return StmtList{stmt}, nil 14 | } 15 | 16 | func AppendStmt(stmtList, stmt interface{}) (StmtList, error) { 17 | return append(stmtList.(StmtList), stmt), nil 18 | } 19 | 20 | func NewStmt(stmtList interface{}) (Stmt, error) { 21 | return Stmt(stmtList.(*token.Token).Lit), nil 22 | } 23 | -------------------------------------------------------------------------------- /example/errorrecovery/doc.go: -------------------------------------------------------------------------------- 1 | package astx 2 | -------------------------------------------------------------------------------- /example/errorrecovery/er.bnf: -------------------------------------------------------------------------------- 1 | /* Lexical elements */ 2 | 3 | _letter : 'a'-'z' | 'A'-'Z' ; 4 | 5 | _digit : '0'-'9' ; 6 | 7 | _idchar : _letter | _digit | '_' ; 8 | 9 | id : (_letter | '_') {_idchar} ; 10 | 11 | !whitespace : ' ' | '\t' | '\n' | '\r' ; 12 | 13 | /* Syntax elements */ 14 | 15 | << import "github.com/goccmack/gocc/example/errorrecovery/ast" >> 16 | 17 | StmtList : 18 | Stmt << ast.NewStmtList($0) >> 19 | | StmtList Stmt << ast.AppendStmt($0, $1) >> 20 | ; 21 | 22 | Stmt : 23 | id << ast.NewStmt($0) >> 24 | | error 25 | ; -------------------------------------------------------------------------------- /example/errorrecovery/er_test.go: -------------------------------------------------------------------------------- 1 | package astx 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/goccmack/gocc/example/errorrecovery/ast" 8 | "github.com/goccmack/gocc/example/errorrecovery/errors" 9 | "github.com/goccmack/gocc/example/errorrecovery/lexer" 10 | "github.com/goccmack/gocc/example/errorrecovery/parser" 11 | ) 12 | 13 | func TestFail(t *testing.T) { 14 | sml, err := test([]byte("a b ; d e f")) 15 | if err != nil { 16 | t.Fail() 17 | } 18 | fmt.Print("output: [\n") 19 | for _, s := range sml { 20 | switch sym := s.(type) { 21 | case *errors.Error: 22 | fmt.Printf("%s\n", sym) 23 | default: 24 | fmt.Printf("\t%v\n", sym) 25 | } 26 | } 27 | fmt.Println("]") 28 | } 29 | 30 | func test(src []byte) (astree ast.StmtList, err error) { 31 | fmt.Printf("input: %s\n", src) 32 | s := lexer.NewLexer(src) 33 | p := parser.NewParser() 34 | a, err := p.Parse(s) 35 | if err == nil { 36 | astree = a.(ast.StmtList) 37 | } 38 | return 39 | } 40 | -------------------------------------------------------------------------------- /example/errorrecovery/lexer/acttab.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package lexer 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/goccmack/gocc/example/errorrecovery/token" 9 | ) 10 | 11 | type ActionTable [NumStates]ActionRow 12 | 13 | type ActionRow struct { 14 | Accept token.Type 15 | Ignore string 16 | } 17 | 18 | func (a ActionRow) String() string { 19 | return fmt.Sprintf("Accept=%d, Ignore=%s", a.Accept, a.Ignore) 20 | } 21 | 22 | var ActTab = ActionTable{ 23 | ActionRow{ // S0 24 | Accept: 0, 25 | Ignore: "", 26 | }, 27 | ActionRow{ // S1 28 | Accept: -1, 29 | Ignore: "!whitespace", 30 | }, 31 | ActionRow{ // S2 32 | Accept: 2, 33 | Ignore: "", 34 | }, 35 | ActionRow{ // S3 36 | Accept: 2, 37 | Ignore: "", 38 | }, 39 | ActionRow{ // S4 40 | Accept: 2, 41 | Ignore: "", 42 | }, 43 | ActionRow{ // S5 44 | Accept: 2, 45 | Ignore: "", 46 | }, 47 | ActionRow{ // S6 48 | Accept: 2, 49 | Ignore: "", 50 | }, 51 | } 52 | -------------------------------------------------------------------------------- /example/errorrecovery/parser/action.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | type action interface { 10 | act() 11 | String() string 12 | } 13 | 14 | type ( 15 | accept bool 16 | shift int // value is next state index 17 | reduce int // value is production index 18 | ) 19 | 20 | func (this accept) act() {} 21 | func (this shift) act() {} 22 | func (this reduce) act() {} 23 | 24 | func (this accept) Equal(that action) bool { 25 | if _, ok := that.(accept); ok { 26 | return true 27 | } 28 | return false 29 | } 30 | 31 | func (this reduce) Equal(that action) bool { 32 | that1, ok := that.(reduce) 33 | if !ok { 34 | return false 35 | } 36 | return this == that1 37 | } 38 | 39 | func (this shift) Equal(that action) bool { 40 | that1, ok := that.(shift) 41 | if !ok { 42 | return false 43 | } 44 | return this == that1 45 | } 46 | 47 | func (this accept) String() string { return "accept(0)" } 48 | func (this shift) String() string { return fmt.Sprintf("shift:%d", this) } 49 | func (this reduce) String() string { 50 | return fmt.Sprintf("reduce:%d(%s)", this, productionsTable[this].String) 51 | } 52 | -------------------------------------------------------------------------------- /example/errorrecovery/parser/actiontable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | type ( 6 | actionTable [numStates]actionRow 7 | actionRow struct { 8 | canRecover bool 9 | actions [numSymbols]action 10 | } 11 | ) 12 | 13 | var actionTab = actionTable{ 14 | actionRow{ // S0 15 | canRecover: true, 16 | actions: [numSymbols]action{ 17 | nil, // INVALID 18 | nil, // ␚ 19 | shift(3), // id 20 | shift(4), // error 21 | }, 22 | }, 23 | actionRow{ // S1 24 | canRecover: true, 25 | actions: [numSymbols]action{ 26 | nil, // INVALID 27 | accept(true), // ␚ 28 | shift(3), // id 29 | shift(4), // error 30 | }, 31 | }, 32 | actionRow{ // S2 33 | canRecover: false, 34 | actions: [numSymbols]action{ 35 | nil, // INVALID 36 | reduce(1), // ␚, reduce: StmtList 37 | reduce(1), // id, reduce: StmtList 38 | reduce(1), // error, reduce: StmtList 39 | }, 40 | }, 41 | actionRow{ // S3 42 | canRecover: false, 43 | actions: [numSymbols]action{ 44 | nil, // INVALID 45 | reduce(3), // ␚, reduce: Stmt 46 | reduce(3), // id, reduce: Stmt 47 | reduce(3), // error, reduce: Stmt 48 | }, 49 | }, 50 | actionRow{ // S4 51 | canRecover: true, 52 | actions: [numSymbols]action{ 53 | nil, // INVALID 54 | reduce(4), // ␚, reduce: Stmt 55 | reduce(4), // id, reduce: Stmt 56 | reduce(4), // error, reduce: Stmt 57 | }, 58 | }, 59 | actionRow{ // S5 60 | canRecover: false, 61 | actions: [numSymbols]action{ 62 | nil, // INVALID 63 | reduce(2), // ␚, reduce: StmtList 64 | reduce(2), // id, reduce: StmtList 65 | reduce(2), // error, reduce: StmtList 66 | }, 67 | }, 68 | } 69 | -------------------------------------------------------------------------------- /example/errorrecovery/parser/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | // Parser-specific user-defined and entirely-optional context, 6 | // accessible as '$Context' in SDT actions. 7 | type Context interface{} 8 | -------------------------------------------------------------------------------- /example/errorrecovery/parser/gototable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | const numNTSymbols = 3 6 | 7 | type ( 8 | gotoTable [numStates]gotoRow 9 | gotoRow [numNTSymbols]int 10 | ) 11 | 12 | var gotoTab = gotoTable{ 13 | gotoRow{ // S0 14 | -1, // S' 15 | 1, // StmtList 16 | 2, // Stmt 17 | }, 18 | gotoRow{ // S1 19 | -1, // S' 20 | -1, // StmtList 21 | 5, // Stmt 22 | }, 23 | gotoRow{ // S2 24 | -1, // S' 25 | -1, // StmtList 26 | -1, // Stmt 27 | }, 28 | gotoRow{ // S3 29 | -1, // S' 30 | -1, // StmtList 31 | -1, // Stmt 32 | }, 33 | gotoRow{ // S4 34 | -1, // S' 35 | -1, // StmtList 36 | -1, // Stmt 37 | }, 38 | gotoRow{ // S5 39 | -1, // S' 40 | -1, // StmtList 41 | -1, // Stmt 42 | }, 43 | } 44 | -------------------------------------------------------------------------------- /example/errorrecovery/parser/productionstable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import "github.com/goccmack/gocc/example/errorrecovery/ast" 6 | 7 | type ( 8 | ProdTab [numProductions]ProdTabEntry 9 | ProdTabEntry struct { 10 | String string 11 | Id string 12 | NTType int 13 | Index int 14 | NumSymbols int 15 | ReduceFunc func([]Attrib, interface{}) (Attrib, error) 16 | } 17 | Attrib interface { 18 | } 19 | ) 20 | 21 | var productionsTable = ProdTab{ 22 | ProdTabEntry{ 23 | String: `S' : StmtList << >>`, 24 | Id: "S'", 25 | NTType: 0, 26 | Index: 0, 27 | NumSymbols: 1, 28 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 29 | return X[0], nil 30 | }, 31 | }, 32 | ProdTabEntry{ 33 | String: `StmtList : Stmt << ast.NewStmtList(X[0]) >>`, 34 | Id: "StmtList", 35 | NTType: 1, 36 | Index: 1, 37 | NumSymbols: 1, 38 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 39 | return ast.NewStmtList(X[0]) 40 | }, 41 | }, 42 | ProdTabEntry{ 43 | String: `StmtList : StmtList Stmt << ast.AppendStmt(X[0], X[1]) >>`, 44 | Id: "StmtList", 45 | NTType: 1, 46 | Index: 2, 47 | NumSymbols: 2, 48 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 49 | return ast.AppendStmt(X[0], X[1]) 50 | }, 51 | }, 52 | ProdTabEntry{ 53 | String: `Stmt : id << ast.NewStmt(X[0]) >>`, 54 | Id: "Stmt", 55 | NTType: 2, 56 | Index: 3, 57 | NumSymbols: 1, 58 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 59 | return ast.NewStmt(X[0]) 60 | }, 61 | }, 62 | ProdTabEntry{ 63 | String: `Stmt : error << >>`, 64 | Id: "Stmt", 65 | NTType: 2, 66 | Index: 4, 67 | NumSymbols: 1, 68 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 69 | return X[0], nil 70 | }, 71 | }, 72 | } 73 | -------------------------------------------------------------------------------- /example/errorrecovery/parser/symbols.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | type symbol struct { 4 | Name string 5 | IsTerminal bool 6 | } 7 | 8 | var symbols = [numSymbols]symbol{ 9 | 10 | { 11 | Name: "INVALID", 12 | IsTerminal: true, 13 | }, 14 | 15 | { 16 | Name: "$", 17 | IsTerminal: true, 18 | }, 19 | 20 | { 21 | Name: "S'", 22 | IsTerminal: false, 23 | }, 24 | 25 | { 26 | Name: "StmtList", 27 | IsTerminal: false, 28 | }, 29 | 30 | { 31 | Name: "Stmt", 32 | IsTerminal: false, 33 | }, 34 | 35 | { 36 | Name: "id", 37 | IsTerminal: true, 38 | }, 39 | 40 | { 41 | Name: "error", 42 | IsTerminal: true, 43 | }, 44 | } 45 | -------------------------------------------------------------------------------- /example/errorrecovery/token/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package token 4 | 5 | // Context allows user-defined data to be associated with the 6 | // lexer/scanner to be associated with each token that lexer 7 | // produces. 8 | type Context interface{} 9 | 10 | // Sourcer is a Context interface which presents a Source() method 11 | // identifying e.g the filename for the current code. 12 | type Sourcer interface { 13 | Source() string 14 | } 15 | -------------------------------------------------------------------------------- /example/errorrecovery/util/rune.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package util 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | func RuneToString(r rune) string { 10 | if r >= 0x20 && r < 0x7f { 11 | return fmt.Sprintf("'%c'", r) 12 | } 13 | switch r { 14 | case 0x07: 15 | return "'\\a'" 16 | case 0x08: 17 | return "'\\b'" 18 | case 0x0C: 19 | return "'\\f'" 20 | case 0x0A: 21 | return "'\\n'" 22 | case 0x0D: 23 | return "'\\r'" 24 | case 0x09: 25 | return "'\\t'" 26 | case 0x0b: 27 | return "'\\v'" 28 | case 0x5c: 29 | return "'\\\\\\'" 30 | case 0x27: 31 | return "'\\''" 32 | case 0x22: 33 | return "'\\\"'" 34 | } 35 | if r < 0x10000 { 36 | return fmt.Sprintf("\\u%04x", r) 37 | } 38 | return fmt.Sprintf("\\U%08x", r) 39 | } 40 | -------------------------------------------------------------------------------- /example/mail/Makefile: -------------------------------------------------------------------------------- 1 | regenerate: 2 | gocc mail.bnf 3 | -------------------------------------------------------------------------------- /example/mail/doc.go: -------------------------------------------------------------------------------- 1 | package mail 2 | -------------------------------------------------------------------------------- /example/mail/lexer/acttab.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package lexer 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/goccmack/gocc/example/mail/token" 9 | ) 10 | 11 | type ActionTable [NumStates]ActionRow 12 | 13 | type ActionRow struct { 14 | Accept token.Type 15 | Ignore string 16 | } 17 | 18 | func (a ActionRow) String() string { 19 | return fmt.Sprintf("Accept=%d, Ignore=%s", a.Accept, a.Ignore) 20 | } 21 | 22 | var ActTab = ActionTable{ 23 | ActionRow{ // S0 24 | Accept: 0, 25 | Ignore: "", 26 | }, 27 | ActionRow{ // S1 28 | Accept: -1, 29 | Ignore: "!whitespace", 30 | }, 31 | ActionRow{ // S2 32 | Accept: 0, 33 | Ignore: "", 34 | }, 35 | ActionRow{ // S3 36 | Accept: 0, 37 | Ignore: "", 38 | }, 39 | ActionRow{ // S4 40 | Accept: 0, 41 | Ignore: "", 42 | }, 43 | ActionRow{ // S5 44 | Accept: 0, 45 | Ignore: "", 46 | }, 47 | ActionRow{ // S6 48 | Accept: 0, 49 | Ignore: "", 50 | }, 51 | ActionRow{ // S7 52 | Accept: 0, 53 | Ignore: "", 54 | }, 55 | ActionRow{ // S8 56 | Accept: 0, 57 | Ignore: "", 58 | }, 59 | ActionRow{ // S9 60 | Accept: 2, 61 | Ignore: "", 62 | }, 63 | ActionRow{ // S10 64 | Accept: 0, 65 | Ignore: "", 66 | }, 67 | ActionRow{ // S11 68 | Accept: 0, 69 | Ignore: "", 70 | }, 71 | ActionRow{ // S12 72 | Accept: 0, 73 | Ignore: "", 74 | }, 75 | ActionRow{ // S13 76 | Accept: 0, 77 | Ignore: "", 78 | }, 79 | ActionRow{ // S14 80 | Accept: 2, 81 | Ignore: "", 82 | }, 83 | } 84 | -------------------------------------------------------------------------------- /example/mail/mail.bnf: -------------------------------------------------------------------------------- 1 | !whitespace : '\t' | '\n' | '\r' | ' ' ; 2 | 3 | _atext : 'A'-'Z' | 'a'-'z' | '0'-'9' 4 | | '!' | '#' | '$' | '%' | '&' | '\'' | '*' | '+' | '-' | '/' 5 | | '=' | '?' | '^' | '_' | '`' | '{' | '|' | '}' | '~' 6 | | '\u0100'-'\U0010FFFF' 7 | ; 8 | 9 | _atom : _atext {_atext} ; 10 | 11 | _dotatom : _atom {'.' _atom} ; 12 | 13 | _quotedpair : '\\' . ; 14 | 15 | _quotedstring : '"' (_quotedpair | .) {_quotedpair | .} '"' ; 16 | 17 | addrspec : (_dotatom | _quotedstring) '@' _dotatom ; 18 | -------------------------------------------------------------------------------- /example/mail/parser_test.go: -------------------------------------------------------------------------------- 1 | package mail 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/goccmack/gocc/example/mail/lexer" 7 | "github.com/goccmack/gocc/example/mail/token" 8 | ) 9 | 10 | var testData1 = map[string]bool{ 11 | "mymail@google.com": true, 12 | "@google.com": false, 13 | `"quoted string"@mymail.com`: true, 14 | `"unclosed quote@mymail.com`: false, 15 | } 16 | 17 | func Test1(t *testing.T) { 18 | for input, ok := range testData1 { 19 | l := lexer.NewLexer([]byte(input)) 20 | tok := l.Scan() 21 | switch { 22 | case tok.Type == token.INVALID: 23 | if ok { 24 | t.Errorf("%s", input) 25 | } 26 | case tok.Type == token.TokMap.Type("addrspec"): 27 | if !ok { 28 | t.Errorf("%s", input) 29 | } 30 | default: 31 | t.Fatalf("This must not happen") 32 | } 33 | } 34 | } 35 | 36 | var checkData2 = []string{ 37 | "addr1@gmail.com", 38 | "addr2@gmail.com", 39 | "addr3@gmail.com", 40 | } 41 | 42 | var testData2 = ` 43 | addr1@gmail.com 44 | addr2@gmail.com 45 | addr3@gmail.com 46 | ` 47 | 48 | func Test2(t *testing.T) { 49 | l := lexer.NewLexer([]byte(testData2)) 50 | num := 0 51 | for tok := l.Scan(); tok.Type == token.TokMap.Type("addrspec"); tok = l.Scan() { 52 | if string(tok.Lit) != checkData2[num] { 53 | t.Errorf("%s != %s", string(tok.Lit), checkData2[num]) 54 | } 55 | num++ 56 | } 57 | if num != len(checkData2) { 58 | t.Fatalf("%d addresses parsed", num) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /example/mail/token/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package token 4 | 5 | // Context allows user-defined data to be associated with the 6 | // lexer/scanner to be associated with each token that lexer 7 | // produces. 8 | type Context interface{} 9 | 10 | // Sourcer is a Context interface which presents a Source() method 11 | // identifying e.g the filename for the current code. 12 | type Sourcer interface { 13 | Source() string 14 | } 15 | -------------------------------------------------------------------------------- /example/mail/util/rune.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package util 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | func RuneToString(r rune) string { 10 | if r >= 0x20 && r < 0x7f { 11 | return fmt.Sprintf("'%c'", r) 12 | } 13 | switch r { 14 | case 0x07: 15 | return "'\\a'" 16 | case 0x08: 17 | return "'\\b'" 18 | case 0x0C: 19 | return "'\\f'" 20 | case 0x0A: 21 | return "'\\n'" 22 | case 0x0D: 23 | return "'\\r'" 24 | case 0x09: 25 | return "'\\t'" 26 | case 0x0b: 27 | return "'\\v'" 28 | case 0x5c: 29 | return "'\\\\\\'" 30 | case 0x27: 31 | return "'\\''" 32 | case 0x22: 33 | return "'\\\"'" 34 | } 35 | if r < 0x10000 { 36 | return fmt.Sprintf("\\u%04x", r) 37 | } 38 | return fmt.Sprintf("\\U%08x", r) 39 | } 40 | -------------------------------------------------------------------------------- /example/nolexer/Makefile: -------------------------------------------------------------------------------- 1 | regenerate: 2 | gocc -no_lexer nolexer.bnf 3 | -------------------------------------------------------------------------------- /example/nolexer/doc.go: -------------------------------------------------------------------------------- 1 | package nolexer 2 | -------------------------------------------------------------------------------- /example/nolexer/nolexer.bnf: -------------------------------------------------------------------------------- 1 | << 2 | import ( 3 | "fmt" 4 | 5 | "github.com/goccmack/gocc/example/nolexer/token" 6 | ) 7 | >> 8 | 9 | Hello : Saying name << func() (Attrib, error) { 10 | fmt.Println(string($1.(*token.Token).Lit)) 11 | return nil, nil 12 | }() 13 | >> 14 | ; 15 | 16 | Saying : "hello" << func() (Attrib, error) { 17 | fmt.Print("hello ") 18 | return nil, nil 19 | }() 20 | >> 21 | | "hiya" << func() (Attrib, error) { 22 | fmt.Print("hiya ") 23 | return nil, nil 24 | }() 25 | >> 26 | ; 27 | -------------------------------------------------------------------------------- /example/nolexer/nolexer_test.go: -------------------------------------------------------------------------------- 1 | package nolexer 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/goccmack/gocc/example/nolexer/parser" 7 | "github.com/goccmack/gocc/example/nolexer/scanner" 8 | ) 9 | 10 | func Test1(t *testing.T) { 11 | S := scanner.NewString("hiya world") 12 | P := parser.NewParser() 13 | if _, e := P.Parse(S); e != nil { 14 | t.Error(e.Error()) 15 | } 16 | } 17 | 18 | func Test2(t *testing.T) { 19 | S := scanner.NewString("hello world") 20 | P := parser.NewParser() 21 | if _, e := P.Parse(S); e != nil { 22 | t.Error(e.Error()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /example/nolexer/parser/action.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | type action interface { 10 | act() 11 | String() string 12 | } 13 | 14 | type ( 15 | accept bool 16 | shift int // value is next state index 17 | reduce int // value is production index 18 | ) 19 | 20 | func (this accept) act() {} 21 | func (this shift) act() {} 22 | func (this reduce) act() {} 23 | 24 | func (this accept) Equal(that action) bool { 25 | if _, ok := that.(accept); ok { 26 | return true 27 | } 28 | return false 29 | } 30 | 31 | func (this reduce) Equal(that action) bool { 32 | that1, ok := that.(reduce) 33 | if !ok { 34 | return false 35 | } 36 | return this == that1 37 | } 38 | 39 | func (this shift) Equal(that action) bool { 40 | that1, ok := that.(shift) 41 | if !ok { 42 | return false 43 | } 44 | return this == that1 45 | } 46 | 47 | func (this accept) String() string { return "accept(0)" } 48 | func (this shift) String() string { return fmt.Sprintf("shift:%d", this) } 49 | func (this reduce) String() string { 50 | return fmt.Sprintf("reduce:%d(%s)", this, productionsTable[this].String) 51 | } 52 | -------------------------------------------------------------------------------- /example/nolexer/parser/actiontable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | type ( 6 | actionTable [numStates]actionRow 7 | actionRow struct { 8 | canRecover bool 9 | actions [numSymbols]action 10 | } 11 | ) 12 | 13 | var actionTab = actionTable{ 14 | actionRow{ // S0 15 | canRecover: false, 16 | actions: [numSymbols]action{ 17 | nil, // INVALID 18 | nil, // ␚ 19 | nil, // name 20 | shift(3), // hello 21 | shift(4), // hiya 22 | }, 23 | }, 24 | actionRow{ // S1 25 | canRecover: false, 26 | actions: [numSymbols]action{ 27 | nil, // INVALID 28 | accept(true), // ␚ 29 | nil, // name 30 | nil, // hello 31 | nil, // hiya 32 | }, 33 | }, 34 | actionRow{ // S2 35 | canRecover: false, 36 | actions: [numSymbols]action{ 37 | nil, // INVALID 38 | nil, // ␚ 39 | shift(5), // name 40 | nil, // hello 41 | nil, // hiya 42 | }, 43 | }, 44 | actionRow{ // S3 45 | canRecover: false, 46 | actions: [numSymbols]action{ 47 | nil, // INVALID 48 | nil, // ␚ 49 | reduce(2), // name, reduce: Saying 50 | nil, // hello 51 | nil, // hiya 52 | }, 53 | }, 54 | actionRow{ // S4 55 | canRecover: false, 56 | actions: [numSymbols]action{ 57 | nil, // INVALID 58 | nil, // ␚ 59 | reduce(3), // name, reduce: Saying 60 | nil, // hello 61 | nil, // hiya 62 | }, 63 | }, 64 | actionRow{ // S5 65 | canRecover: false, 66 | actions: [numSymbols]action{ 67 | nil, // INVALID 68 | reduce(1), // ␚, reduce: Hello 69 | nil, // name 70 | nil, // hello 71 | nil, // hiya 72 | }, 73 | }, 74 | } 75 | -------------------------------------------------------------------------------- /example/nolexer/parser/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | // Parser-specific user-defined and entirely-optional context, 6 | // accessible as '$Context' in SDT actions. 7 | type Context interface{} 8 | -------------------------------------------------------------------------------- /example/nolexer/parser/gototable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | const numNTSymbols = 3 6 | 7 | type ( 8 | gotoTable [numStates]gotoRow 9 | gotoRow [numNTSymbols]int 10 | ) 11 | 12 | var gotoTab = gotoTable{ 13 | gotoRow{ // S0 14 | -1, // S' 15 | 1, // Hello 16 | 2, // Saying 17 | }, 18 | gotoRow{ // S1 19 | -1, // S' 20 | -1, // Hello 21 | -1, // Saying 22 | }, 23 | gotoRow{ // S2 24 | -1, // S' 25 | -1, // Hello 26 | -1, // Saying 27 | }, 28 | gotoRow{ // S3 29 | -1, // S' 30 | -1, // Hello 31 | -1, // Saying 32 | }, 33 | gotoRow{ // S4 34 | -1, // S' 35 | -1, // Hello 36 | -1, // Saying 37 | }, 38 | gotoRow{ // S5 39 | -1, // S' 40 | -1, // Hello 41 | -1, // Saying 42 | }, 43 | } 44 | -------------------------------------------------------------------------------- /example/nolexer/parser/productionstable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/goccmack/gocc/example/nolexer/token" 9 | ) 10 | 11 | type ( 12 | ProdTab [numProductions]ProdTabEntry 13 | ProdTabEntry struct { 14 | String string 15 | Id string 16 | NTType int 17 | Index int 18 | NumSymbols int 19 | ReduceFunc func([]Attrib, interface{}) (Attrib, error) 20 | } 21 | Attrib interface { 22 | } 23 | ) 24 | 25 | var productionsTable = ProdTab{ 26 | ProdTabEntry{ 27 | String: `S' : Hello << >>`, 28 | Id: "S'", 29 | NTType: 0, 30 | Index: 0, 31 | NumSymbols: 1, 32 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 33 | return X[0], nil 34 | }, 35 | }, 36 | ProdTabEntry{ 37 | String: `Hello : Saying name << func() (Attrib, error) { 38 | fmt.Println(string(X[1].(*token.Token).Lit)) 39 | return nil, nil 40 | }() >>`, 41 | Id: "Hello", 42 | NTType: 1, 43 | Index: 1, 44 | NumSymbols: 2, 45 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 46 | return func() (Attrib, error) { 47 | fmt.Println(string(X[1].(*token.Token).Lit)) 48 | return nil, nil 49 | }() 50 | }, 51 | }, 52 | ProdTabEntry{ 53 | String: `Saying : "hello" << func() (Attrib, error) { 54 | fmt.Print("hello ") 55 | return nil, nil 56 | }() >>`, 57 | Id: "Saying", 58 | NTType: 2, 59 | Index: 2, 60 | NumSymbols: 1, 61 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 62 | return func() (Attrib, error) { 63 | fmt.Print("hello ") 64 | return nil, nil 65 | }() 66 | }, 67 | }, 68 | ProdTabEntry{ 69 | String: `Saying : "hiya" << func() (Attrib, error) { 70 | fmt.Print("hiya ") 71 | return nil, nil 72 | }() >>`, 73 | Id: "Saying", 74 | NTType: 2, 75 | Index: 3, 76 | NumSymbols: 1, 77 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 78 | return func() (Attrib, error) { 79 | fmt.Print("hiya ") 80 | return nil, nil 81 | }() 82 | }, 83 | }, 84 | } 85 | -------------------------------------------------------------------------------- /example/nolexer/scanner/scanner.go: -------------------------------------------------------------------------------- 1 | package scanner 2 | 3 | import ( 4 | "github.com/goccmack/gocc/example/nolexer/token" 5 | ) 6 | 7 | type Scanner struct { 8 | src []byte 9 | pos int 10 | } 11 | 12 | func NewString(s string) *Scanner { 13 | return &Scanner{[]byte(s), 0} 14 | } 15 | 16 | func isWhiteSpace(c byte) bool { 17 | return c == ' ' || 18 | c == '\t' || 19 | c == '\n' || 20 | c == '\r' 21 | } 22 | 23 | func (S *Scanner) skipWhiteSpace() { 24 | for S.pos < len(S.src) && isWhiteSpace(S.src[S.pos]) { 25 | S.pos++ 26 | } 27 | } 28 | 29 | func (S *Scanner) scanId() string { 30 | pos := S.pos 31 | for S.pos < len(S.src) && !isWhiteSpace(S.src[S.pos]) { 32 | S.pos++ 33 | } 34 | S.pos++ 35 | return string(S.src[pos : S.pos-1]) 36 | } 37 | 38 | func (S *Scanner) Scan() (tok *token.Token) { 39 | S.skipWhiteSpace() 40 | 41 | if S.pos >= len(S.src) { 42 | return &token.Token{Type: token.EOF} 43 | } 44 | 45 | pos := S.pos 46 | 47 | lit := S.scanId() 48 | switch lit { 49 | case "hiya": 50 | return &token.Token{Type: token.TokMap.Type("hiya"), 51 | Lit: []byte("hiya"), 52 | Pos: token.Pos{Offset: pos}} 53 | case "hello": 54 | return &token.Token{Type: token.TokMap.Type("hello"), 55 | Lit: []byte("hello"), 56 | Pos: token.Pos{Offset: pos}} 57 | default: 58 | return &token.Token{Type: token.TokMap.Type("name"), 59 | Lit: []byte(lit), 60 | Pos: token.Pos{Offset: pos}} 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /example/nolexer/token/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package token 4 | 5 | // Context allows user-defined data to be associated with the 6 | // lexer/scanner to be associated with each token that lexer 7 | // produces. 8 | type Context interface{} 9 | 10 | // Sourcer is a Context interface which presents a Source() method 11 | // identifying e.g the filename for the current code. 12 | type Sourcer interface { 13 | Source() string 14 | } 15 | -------------------------------------------------------------------------------- /example/nolexer/util/rune.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package util 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | func RuneToString(r rune) string { 10 | if r >= 0x20 && r < 0x7f { 11 | return fmt.Sprintf("'%c'", r) 12 | } 13 | switch r { 14 | case 0x07: 15 | return "'\\a'" 16 | case 0x08: 17 | return "'\\b'" 18 | case 0x0C: 19 | return "'\\f'" 20 | case 0x0A: 21 | return "'\\n'" 22 | case 0x0D: 23 | return "'\\r'" 24 | case 0x09: 25 | return "'\\t'" 26 | case 0x0b: 27 | return "'\\v'" 28 | case 0x5c: 29 | return "'\\\\\\'" 30 | case 0x27: 31 | return "'\\''" 32 | case 0x22: 33 | return "'\\\"'" 34 | } 35 | if r < 0x10000 { 36 | return fmt.Sprintf("\\u%04x", r) 37 | } 38 | return fmt.Sprintf("\\U%08x", r) 39 | } 40 | -------------------------------------------------------------------------------- /example/rr/Makefile: -------------------------------------------------------------------------------- 1 | regenerate: 2 | gocc -a rr.bnf 3 | -------------------------------------------------------------------------------- /example/rr/doc.go: -------------------------------------------------------------------------------- 1 | package rr 2 | -------------------------------------------------------------------------------- /example/rr/lexer/acttab.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package lexer 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/goccmack/gocc/example/rr/token" 9 | ) 10 | 11 | type ActionTable [NumStates]ActionRow 12 | 13 | type ActionRow struct { 14 | Accept token.Type 15 | Ignore string 16 | } 17 | 18 | func (a ActionRow) String() string { 19 | return fmt.Sprintf("Accept=%d, Ignore=%s", a.Accept, a.Ignore) 20 | } 21 | 22 | var ActTab = ActionTable{ 23 | ActionRow{ // S0 24 | Accept: 0, 25 | Ignore: "", 26 | }, 27 | ActionRow{ // S1 28 | Accept: -1, 29 | Ignore: "!whitespace", 30 | }, 31 | ActionRow{ // S2 32 | Accept: 2, 33 | Ignore: "", 34 | }, 35 | ActionRow{ // S3 36 | Accept: 3, 37 | Ignore: "", 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /example/rr/lexer/transitiontable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package lexer 4 | 5 | /* 6 | Let s be the current state 7 | Let r be the current input rune 8 | transitionTable[s](r) returns the next state. 9 | */ 10 | type TransitionTable [NumStates]func(rune) int 11 | 12 | var TransTab = TransitionTable{ 13 | // S0 14 | func(r rune) int { 15 | switch { 16 | case r == 9: // ['\t','\t'] 17 | return 1 18 | case r == 10: // ['\n','\n'] 19 | return 1 20 | case r == 13: // ['\r','\r'] 21 | return 1 22 | case r == 32: // [' ',' '] 23 | return 1 24 | case r == 97: // ['a','a'] 25 | return 2 26 | case r == 99: // ['c','c'] 27 | return 3 28 | } 29 | return NoState 30 | }, 31 | // S1 32 | func(r rune) int { 33 | switch { 34 | } 35 | return NoState 36 | }, 37 | // S2 38 | func(r rune) int { 39 | switch { 40 | } 41 | return NoState 42 | }, 43 | // S3 44 | func(r rune) int { 45 | switch { 46 | } 47 | return NoState 48 | }, 49 | } 50 | -------------------------------------------------------------------------------- /example/rr/parser/action.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | type action interface { 10 | act() 11 | String() string 12 | } 13 | 14 | type ( 15 | accept bool 16 | shift int // value is next state index 17 | reduce int // value is production index 18 | ) 19 | 20 | func (this accept) act() {} 21 | func (this shift) act() {} 22 | func (this reduce) act() {} 23 | 24 | func (this accept) Equal(that action) bool { 25 | if _, ok := that.(accept); ok { 26 | return true 27 | } 28 | return false 29 | } 30 | 31 | func (this reduce) Equal(that action) bool { 32 | that1, ok := that.(reduce) 33 | if !ok { 34 | return false 35 | } 36 | return this == that1 37 | } 38 | 39 | func (this shift) Equal(that action) bool { 40 | that1, ok := that.(shift) 41 | if !ok { 42 | return false 43 | } 44 | return this == that1 45 | } 46 | 47 | func (this accept) String() string { return "accept(0)" } 48 | func (this shift) String() string { return fmt.Sprintf("shift:%d", this) } 49 | func (this reduce) String() string { 50 | return fmt.Sprintf("reduce:%d(%s)", this, productionsTable[this].String) 51 | } 52 | -------------------------------------------------------------------------------- /example/rr/parser/actiontable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | type ( 6 | actionTable [numStates]actionRow 7 | actionRow struct { 8 | canRecover bool 9 | actions [numSymbols]action 10 | } 11 | ) 12 | 13 | var actionTab = actionTable{ 14 | actionRow{ // S0 15 | canRecover: false, 16 | actions: [numSymbols]action{ 17 | nil, // INVALID 18 | nil, // ␚ 19 | shift(4), // a 20 | shift(5), // c 21 | }, 22 | }, 23 | actionRow{ // S1 24 | canRecover: false, 25 | actions: [numSymbols]action{ 26 | nil, // INVALID 27 | accept(true), // ␚ 28 | nil, // a 29 | nil, // c 30 | }, 31 | }, 32 | actionRow{ // S2 33 | canRecover: false, 34 | actions: [numSymbols]action{ 35 | nil, // INVALID 36 | reduce(1), // ␚, reduce: RR 37 | shift(6), // a 38 | nil, // c 39 | }, 40 | }, 41 | actionRow{ // S3 42 | canRecover: false, 43 | actions: [numSymbols]action{ 44 | nil, // INVALID 45 | reduce(2), // ␚, reduce: RR 46 | nil, // a 47 | nil, // c 48 | }, 49 | }, 50 | actionRow{ // S4 51 | canRecover: false, 52 | actions: [numSymbols]action{ 53 | nil, // INVALID 54 | reduce(3), // ␚, reduce: B 55 | reduce(4), // a, reduce: A 56 | nil, // c 57 | }, 58 | }, 59 | actionRow{ // S5 60 | canRecover: false, 61 | actions: [numSymbols]action{ 62 | nil, // INVALID 63 | reduce(6), // ␚, reduce: A 64 | reduce(6), // a, reduce: A 65 | nil, // c 66 | }, 67 | }, 68 | actionRow{ // S6 69 | canRecover: false, 70 | actions: [numSymbols]action{ 71 | nil, // INVALID 72 | reduce(5), // ␚, reduce: A 73 | reduce(5), // a, reduce: A 74 | nil, // c 75 | }, 76 | }, 77 | } 78 | -------------------------------------------------------------------------------- /example/rr/parser/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | // Parser-specific user-defined and entirely-optional context, 6 | // accessible as '$Context' in SDT actions. 7 | type Context interface{} 8 | -------------------------------------------------------------------------------- /example/rr/parser/gototable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | const numNTSymbols = 4 6 | 7 | type ( 8 | gotoTable [numStates]gotoRow 9 | gotoRow [numNTSymbols]int 10 | ) 11 | 12 | var gotoTab = gotoTable{ 13 | gotoRow{ // S0 14 | -1, // S' 15 | 1, // RR 16 | 3, // B 17 | 2, // A 18 | }, 19 | gotoRow{ // S1 20 | -1, // S' 21 | -1, // RR 22 | -1, // B 23 | -1, // A 24 | }, 25 | gotoRow{ // S2 26 | -1, // S' 27 | -1, // RR 28 | -1, // B 29 | -1, // A 30 | }, 31 | gotoRow{ // S3 32 | -1, // S' 33 | -1, // RR 34 | -1, // B 35 | -1, // A 36 | }, 37 | gotoRow{ // S4 38 | -1, // S' 39 | -1, // RR 40 | -1, // B 41 | -1, // A 42 | }, 43 | gotoRow{ // S5 44 | -1, // S' 45 | -1, // RR 46 | -1, // B 47 | -1, // A 48 | }, 49 | gotoRow{ // S6 50 | -1, // S' 51 | -1, // RR 52 | -1, // B 53 | -1, // A 54 | }, 55 | } 56 | -------------------------------------------------------------------------------- /example/rr/parser/productionstable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | type ( 6 | ProdTab [numProductions]ProdTabEntry 7 | ProdTabEntry struct { 8 | String string 9 | Id string 10 | NTType int 11 | Index int 12 | NumSymbols int 13 | ReduceFunc func([]Attrib, interface{}) (Attrib, error) 14 | } 15 | Attrib interface { 16 | } 17 | ) 18 | 19 | var productionsTable = ProdTab{ 20 | ProdTabEntry{ 21 | String: `S' : RR << >>`, 22 | Id: "S'", 23 | NTType: 0, 24 | Index: 0, 25 | NumSymbols: 1, 26 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 27 | return X[0], nil 28 | }, 29 | }, 30 | ProdTabEntry{ 31 | String: `RR : A << >>`, 32 | Id: "RR", 33 | NTType: 1, 34 | Index: 1, 35 | NumSymbols: 1, 36 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 37 | return X[0], nil 38 | }, 39 | }, 40 | ProdTabEntry{ 41 | String: `RR : B << >>`, 42 | Id: "RR", 43 | NTType: 1, 44 | Index: 2, 45 | NumSymbols: 1, 46 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 47 | return X[0], nil 48 | }, 49 | }, 50 | ProdTabEntry{ 51 | String: `B : a << "B ", nil >>`, 52 | Id: "B", 53 | NTType: 2, 54 | Index: 3, 55 | NumSymbols: 1, 56 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 57 | return "B ", nil 58 | }, 59 | }, 60 | ProdTabEntry{ 61 | String: `A : a << "A0 ", nil >>`, 62 | Id: "A", 63 | NTType: 3, 64 | Index: 4, 65 | NumSymbols: 1, 66 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 67 | return "A0 ", nil 68 | }, 69 | }, 70 | ProdTabEntry{ 71 | String: `A : A a << "A1 ", nil >>`, 72 | Id: "A", 73 | NTType: 3, 74 | Index: 5, 75 | NumSymbols: 2, 76 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 77 | return "A1 ", nil 78 | }, 79 | }, 80 | ProdTabEntry{ 81 | String: `A : c << "A2 ", nil >>`, 82 | Id: "A", 83 | NTType: 3, 84 | Index: 6, 85 | NumSymbols: 1, 86 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 87 | return "A2 ", nil 88 | }, 89 | }, 90 | } 91 | -------------------------------------------------------------------------------- /example/rr/rr.bnf: -------------------------------------------------------------------------------- 1 | //Copyright 2012 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /* Lexical elements */ 16 | a : 'a' ; 17 | 18 | c : 'c' ; 19 | 20 | !whitespace : ' ' | '\t' | '\n' | '\r' ; 21 | 22 | /* Syntax elements */ 23 | 24 | RR : A | B ; 25 | 26 | B : 27 | a << "B ", nil >> 28 | ; 29 | 30 | A : 31 | a << "A0 ", nil >> 32 | | A a << "A1 ", nil >> 33 | | c << "A2 ", nil >> 34 | ; 35 | -------------------------------------------------------------------------------- /example/rr/rr_test.go: -------------------------------------------------------------------------------- 1 | //Copyright 2012 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package rr 16 | 17 | import ( 18 | "fmt" 19 | "testing" 20 | 21 | "github.com/goccmack/gocc/example/rr/lexer" 22 | "github.com/goccmack/gocc/example/rr/parser" 23 | ) 24 | 25 | func parse(src string) (ast string, err error) { 26 | l := lexer.NewLexer([]byte(src)) 27 | p := parser.NewParser() 28 | res, err := p.Parse(l) 29 | if err == nil { 30 | ast = res.(string) 31 | } 32 | return 33 | } 34 | 35 | func test(t *testing.T, src, exp string) { 36 | ast, err := parse(src) 37 | if err != nil { 38 | t.Fatalf("\tError: %s\n", err.Error()) 39 | } 40 | if ast != exp { 41 | t.Fatalf("\tError: ast= `%s`\n", ast) 42 | } 43 | } 44 | 45 | type TD struct { 46 | src string 47 | exp string 48 | } 49 | 50 | var testData = []TD{ 51 | {"a", "B "}, 52 | {"a a", "A1 "}, 53 | {"a a a", "A1 "}, 54 | {"c a", "A1 "}, 55 | {"c a a a a", "A1 "}, 56 | } 57 | 58 | func Test(t *testing.T) { 59 | for _, td := range testData { 60 | fmt.Printf("\tsrc: `%s`; exp: `%s`\n", td.src, td.exp) 61 | test(t, td.src, td.exp) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /example/rr/token/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package token 4 | 5 | // Context allows user-defined data to be associated with the 6 | // lexer/scanner to be associated with each token that lexer 7 | // produces. 8 | type Context interface{} 9 | 10 | // Sourcer is a Context interface which presents a Source() method 11 | // identifying e.g the filename for the current code. 12 | type Sourcer interface { 13 | Source() string 14 | } 15 | -------------------------------------------------------------------------------- /example/rr/util/rune.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package util 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | func RuneToString(r rune) string { 10 | if r >= 0x20 && r < 0x7f { 11 | return fmt.Sprintf("'%c'", r) 12 | } 13 | switch r { 14 | case 0x07: 15 | return "'\\a'" 16 | case 0x08: 17 | return "'\\b'" 18 | case 0x0C: 19 | return "'\\f'" 20 | case 0x0A: 21 | return "'\\n'" 22 | case 0x0D: 23 | return "'\\r'" 24 | case 0x09: 25 | return "'\\t'" 26 | case 0x0b: 27 | return "'\\v'" 28 | case 0x5c: 29 | return "'\\\\\\'" 30 | case 0x27: 31 | return "'\\''" 32 | case 0x22: 33 | return "'\\\"'" 34 | } 35 | if r < 0x10000 { 36 | return fmt.Sprintf("\\u%04x", r) 37 | } 38 | return fmt.Sprintf("\\U%08x", r) 39 | } 40 | -------------------------------------------------------------------------------- /example/sr/Makefile: -------------------------------------------------------------------------------- 1 | regenerate: 2 | gocc -a sr.bnf 3 | -------------------------------------------------------------------------------- /example/sr/doc.go: -------------------------------------------------------------------------------- 1 | package sr 2 | -------------------------------------------------------------------------------- /example/sr/lexer/acttab.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package lexer 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/goccmack/gocc/example/sr/token" 9 | ) 10 | 11 | type ActionTable [NumStates]ActionRow 12 | 13 | type ActionRow struct { 14 | Accept token.Type 15 | Ignore string 16 | } 17 | 18 | func (a ActionRow) String() string { 19 | return fmt.Sprintf("Accept=%d, Ignore=%s", a.Accept, a.Ignore) 20 | } 21 | 22 | var ActTab = ActionTable{ 23 | ActionRow{ // S0 24 | Accept: 0, 25 | Ignore: "", 26 | }, 27 | ActionRow{ // S1 28 | Accept: -1, 29 | Ignore: "!whitespace", 30 | }, 31 | ActionRow{ // S2 32 | Accept: 3, 33 | Ignore: "", 34 | }, 35 | ActionRow{ // S3 36 | Accept: 3, 37 | Ignore: "", 38 | }, 39 | ActionRow{ // S4 40 | Accept: 3, 41 | Ignore: "", 42 | }, 43 | ActionRow{ // S5 44 | Accept: 3, 45 | Ignore: "", 46 | }, 47 | ActionRow{ // S6 48 | Accept: 3, 49 | Ignore: "", 50 | }, 51 | ActionRow{ // S7 52 | Accept: 3, 53 | Ignore: "", 54 | }, 55 | ActionRow{ // S8 56 | Accept: 3, 57 | Ignore: "", 58 | }, 59 | ActionRow{ // S9 60 | Accept: 3, 61 | Ignore: "", 62 | }, 63 | ActionRow{ // S10 64 | Accept: 3, 65 | Ignore: "", 66 | }, 67 | ActionRow{ // S11 68 | Accept: 2, 69 | Ignore: "", 70 | }, 71 | ActionRow{ // S12 72 | Accept: 3, 73 | Ignore: "", 74 | }, 75 | ActionRow{ // S13 76 | Accept: 3, 77 | Ignore: "", 78 | }, 79 | ActionRow{ // S14 80 | Accept: 3, 81 | Ignore: "", 82 | }, 83 | ActionRow{ // S15 84 | Accept: 5, 85 | Ignore: "", 86 | }, 87 | ActionRow{ // S16 88 | Accept: 4, 89 | Ignore: "", 90 | }, 91 | } 92 | -------------------------------------------------------------------------------- /example/sr/parser/action.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | type action interface { 10 | act() 11 | String() string 12 | } 13 | 14 | type ( 15 | accept bool 16 | shift int // value is next state index 17 | reduce int // value is production index 18 | ) 19 | 20 | func (this accept) act() {} 21 | func (this shift) act() {} 22 | func (this reduce) act() {} 23 | 24 | func (this accept) Equal(that action) bool { 25 | if _, ok := that.(accept); ok { 26 | return true 27 | } 28 | return false 29 | } 30 | 31 | func (this reduce) Equal(that action) bool { 32 | that1, ok := that.(reduce) 33 | if !ok { 34 | return false 35 | } 36 | return this == that1 37 | } 38 | 39 | func (this shift) Equal(that action) bool { 40 | that1, ok := that.(shift) 41 | if !ok { 42 | return false 43 | } 44 | return this == that1 45 | } 46 | 47 | func (this accept) String() string { return "accept(0)" } 48 | func (this shift) String() string { return fmt.Sprintf("shift:%d", this) } 49 | func (this reduce) String() string { 50 | return fmt.Sprintf("reduce:%d(%s)", this, productionsTable[this].String) 51 | } 52 | -------------------------------------------------------------------------------- /example/sr/parser/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | // Parser-specific user-defined and entirely-optional context, 6 | // accessible as '$Context' in SDT actions. 7 | type Context interface{} 8 | -------------------------------------------------------------------------------- /example/sr/parser/gototable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | const numNTSymbols = 2 6 | 7 | type ( 8 | gotoTable [numStates]gotoRow 9 | gotoRow [numNTSymbols]int 10 | ) 11 | 12 | var gotoTab = gotoTable{ 13 | gotoRow{ // S0 14 | -1, // S' 15 | 1, // Stmt 16 | }, 17 | gotoRow{ // S1 18 | -1, // S' 19 | -1, // Stmt 20 | }, 21 | gotoRow{ // S2 22 | -1, // S' 23 | -1, // Stmt 24 | }, 25 | gotoRow{ // S3 26 | -1, // S' 27 | -1, // Stmt 28 | }, 29 | gotoRow{ // S4 30 | -1, // S' 31 | -1, // Stmt 32 | }, 33 | gotoRow{ // S5 34 | -1, // S' 35 | 6, // Stmt 36 | }, 37 | gotoRow{ // S6 38 | -1, // S' 39 | -1, // Stmt 40 | }, 41 | gotoRow{ // S7 42 | -1, // S' 43 | -1, // Stmt 44 | }, 45 | gotoRow{ // S8 46 | -1, // S' 47 | -1, // Stmt 48 | }, 49 | gotoRow{ // S9 50 | -1, // S' 51 | 11, // Stmt 52 | }, 53 | gotoRow{ // S10 54 | -1, // S' 55 | -1, // Stmt 56 | }, 57 | gotoRow{ // S11 58 | -1, // S' 59 | -1, // Stmt 60 | }, 61 | gotoRow{ // S12 62 | -1, // S' 63 | 13, // Stmt 64 | }, 65 | gotoRow{ // S13 66 | -1, // S' 67 | -1, // Stmt 68 | }, 69 | gotoRow{ // S14 70 | -1, // S' 71 | 15, // Stmt 72 | }, 73 | gotoRow{ // S15 74 | -1, // S' 75 | -1, // Stmt 76 | }, 77 | } 78 | -------------------------------------------------------------------------------- /example/sr/parser/productionstable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import "github.com/goccmack/gocc/example/sr/ast" 6 | 7 | type ( 8 | ProdTab [numProductions]ProdTabEntry 9 | ProdTabEntry struct { 10 | String string 11 | Id string 12 | NTType int 13 | Index int 14 | NumSymbols int 15 | ReduceFunc func([]Attrib, interface{}) (Attrib, error) 16 | } 17 | Attrib interface { 18 | } 19 | ) 20 | 21 | var productionsTable = ProdTab{ 22 | ProdTabEntry{ 23 | String: `S' : Stmt << >>`, 24 | Id: "S'", 25 | NTType: 0, 26 | Index: 0, 27 | NumSymbols: 1, 28 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 29 | return X[0], nil 30 | }, 31 | }, 32 | ProdTabEntry{ 33 | String: `Stmt : "if" id "then" Stmt << ast.NewIf(X[1], X[3]), nil >>`, 34 | Id: "Stmt", 35 | NTType: 1, 36 | Index: 1, 37 | NumSymbols: 4, 38 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 39 | return ast.NewIf(X[1], X[3]), nil 40 | }, 41 | }, 42 | ProdTabEntry{ 43 | String: `Stmt : "if" id "then" Stmt "else" Stmt << ast.NewIfElse(X[1], X[3], X[5]), nil >>`, 44 | Id: "Stmt", 45 | NTType: 1, 46 | Index: 2, 47 | NumSymbols: 6, 48 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 49 | return ast.NewIfElse(X[1], X[3], X[5]), nil 50 | }, 51 | }, 52 | ProdTabEntry{ 53 | String: `Stmt : id << ast.NewIdStmt(X[0]), nil >>`, 54 | Id: "Stmt", 55 | NTType: 1, 56 | Index: 3, 57 | NumSymbols: 1, 58 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 59 | return ast.NewIdStmt(X[0]), nil 60 | }, 61 | }, 62 | } 63 | -------------------------------------------------------------------------------- /example/sr/sr.bnf: -------------------------------------------------------------------------------- 1 | //Copyright 2012 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /* Lexical elements */ 16 | 17 | _letter : 'a'-'z' | 'A'-'Z' ; 18 | 19 | _digit : '0'-'9' ; 20 | 21 | _idchar : _letter | _digit | '_' ; 22 | 23 | id : (_letter | '_') {_idchar} ; 24 | 25 | !whitespace : ' ' | '\t' | '\n' | '\r' ; 26 | 27 | /* Syntax elements */ 28 | 29 | << import "github.com/goccmack/gocc/example/sr/ast" >> 30 | 31 | Stmt : 32 | "if" id "then" Stmt << ast.NewIf($1, $3), nil >> 33 | | "if" id "then" Stmt "else" Stmt << ast.NewIfElse($1, $3, $5), nil >> 34 | | id << ast.NewIdStmt($0), nil >> 35 | ; 36 | 37 | -------------------------------------------------------------------------------- /example/sr/sr_test.go: -------------------------------------------------------------------------------- 1 | package sr 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/goccmack/gocc/example/sr/ast" 7 | "github.com/goccmack/gocc/example/sr/lexer" 8 | "github.com/goccmack/gocc/example/sr/parser" 9 | ) 10 | 11 | func parse(src string) (stmt ast.Stmt, err error) { 12 | lex := lexer.NewLexer([]byte(src)) 13 | p := parser.NewParser() 14 | if res, err := p.Parse(lex); err == nil { 15 | stmt = res.(ast.Stmt) 16 | } 17 | return 18 | } 19 | 20 | func Test1(t *testing.T) { 21 | stmt, err := parse("if c1 then s1") 22 | if err != nil { 23 | t.Fatal(err.Error()) 24 | } 25 | ifs, ok := stmt.(*ast.If) 26 | if !ok { 27 | t.Fatalf("sr_test.Test1: stmt is not *ast.If") 28 | } 29 | if !ifs.MatchIf("c1", ast.IdStmt("s1")) { 30 | t.Fail() 31 | } 32 | } 33 | 34 | func Test2(t *testing.T) { 35 | stmt, err := parse("if c1 then s1 else s2") 36 | if err != nil { 37 | t.Fatal(err.Error()) 38 | } 39 | ifes, ok := stmt.(*ast.IfElse) 40 | if !ok { 41 | t.Fatalf("stmt is not *ast.IfElse") 42 | } 43 | if !ifes.MatchIfElse("c1", ast.IdStmt("s1"), ast.IdStmt("s2")) { 44 | t.Fail() 45 | } 46 | } 47 | 48 | func Test3(t *testing.T) { 49 | stmt, err := parse("if c1 then if c2 then s2 else s3") 50 | if err != nil { 51 | t.Fatal(err.Error()) 52 | } 53 | ifs, ok := stmt.(*ast.If) 54 | if !ok { 55 | t.Fatalf("stmt is not *ast.IfElse") 56 | } 57 | ife2 := &ast.IfElse{C: "c2", S1: ast.IdStmt("s2"), S2: ast.IdStmt("s3")} 58 | if !ifs.MatchIf("c1", ife2) { 59 | t.Fail() 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /example/sr/token/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package token 4 | 5 | // Context allows user-defined data to be associated with the 6 | // lexer/scanner to be associated with each token that lexer 7 | // produces. 8 | type Context interface{} 9 | 10 | // Sourcer is a Context interface which presents a Source() method 11 | // identifying e.g the filename for the current code. 12 | type Sourcer interface { 13 | Source() string 14 | } 15 | -------------------------------------------------------------------------------- /example/sr/util/rune.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package util 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | func RuneToString(r rune) string { 10 | if r >= 0x20 && r < 0x7f { 11 | return fmt.Sprintf("'%c'", r) 12 | } 13 | switch r { 14 | case 0x07: 15 | return "'\\a'" 16 | case 0x08: 17 | return "'\\b'" 18 | case 0x0C: 19 | return "'\\f'" 20 | case 0x0A: 21 | return "'\\n'" 22 | case 0x0D: 23 | return "'\\r'" 24 | case 0x09: 25 | return "'\\t'" 26 | case 0x0b: 27 | return "'\\v'" 28 | case 0x5c: 29 | return "'\\\\\\'" 30 | case 0x27: 31 | return "'\\''" 32 | case 0x22: 33 | return "'\\\"'" 34 | } 35 | if r < 0x10000 { 36 | return fmt.Sprintf("\\u%04x", r) 37 | } 38 | return fmt.Sprintf("\\U%08x", r) 39 | } 40 | -------------------------------------------------------------------------------- /example/usercontext/Makefile: -------------------------------------------------------------------------------- 1 | regenerate: 2 | gocc -a example.bnf 3 | -------------------------------------------------------------------------------- /example/usercontext/README.md: -------------------------------------------------------------------------------- 1 | Lexical and Parser user-defined context data 2 | ============================================ 3 | 4 | For advanced use cases, it is sometimes helpful to be able to have 5 | additional data available in either the parsing context, such as 6 | sdt actions, or the lexical context, on the lexer or the tokens 7 | it produces. 8 | 9 | Distinction between Lexical and Parser Context 10 | ---------------------------------------------- 11 | 12 | Both `parser` and `token` define `Context` as `interface{}`. 13 | 14 | Gocc does not care if the parser and lexical contexts are the same, or 15 | whether you use one and not the other. 16 | 17 | Lexical Context 18 | --------------- 19 | 20 | When the lexer.Lexer object is configured with a non-nil Context value, 21 | the value will be assigned to the Pos.Context property of every token 22 | the lexer generates. 23 | 24 | If you are parsing multiple files, this could allow you to inform the 25 | user that tokenA is redeclared in file2.txt after being previously 26 | declared in file1.txt, rather than simply "I've seen tokenA before". 27 | 28 | Assigning: 29 | ``` 30 | // assigning 31 | l := lexer.NewLexer() 32 | l.Context = &MyContext{ /* populate fields */ } 33 | // or just 34 | l.Context = filename 35 | ``` 36 | 37 | Use (assumes MyContext has method 'Source()' that returns filename) 38 | ``` 39 | func duplicate(newToken, oldToken *token.Token) error { 40 | newPos, oldPos := newToken.Pos, oldToken.Pos 41 | 42 | return fmt.Errorf("%s:%d:%d: error: '%s' redefined.\n%s:%d:%d: previous definition", 43 | newPos.Context.(*MyContext).Source(), newPos.Line, newPos.Column, 44 | string(newToken.Lit), 45 | oldPos.Context.(*MyContext).Source(), oldPos.Line, oldPos.Column) 46 | ``` 47 | 48 | Parser Context 49 | -------------- 50 | 51 | This allows you to surface contextual information when invoking SDT actions. It 52 | corresponds to the `Context` property of the `parser.Parser` class, and can be 53 | accessed with the SDT token `$Context`. 54 | 55 | Example: 56 | 57 | _bnf_ 58 | ``` 59 | Identifier: identifier << ast.NewIdentifier($0, $Context); 60 | ``` 61 | 62 | _ast/main.go_ 63 | ``` 64 | func NewIdentifier(nameAttr Attrib, context interface{}) (string, error) { 65 | name := string(nameAttr.(*token.Token).Lit) 66 | if previous, exists := context.(*ParseContext).Identifiers[name]; exists { 67 | ... 68 | ``` 69 | 70 | -------------------------------------------------------------------------------- /example/usercontext/ast/main.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/goccmack/gocc/example/usercontext/token" 7 | ) 8 | 9 | type Attrib interface{} 10 | 11 | // Demonstrates how Lexical and Parser context might differ. 12 | type LexicalContext struct { 13 | SourceFile string 14 | ForbiddenWords []string 15 | } 16 | 17 | // Source implements the lexer.Sourcer interface. 18 | func (lc *LexicalContext) Source() string { 19 | return lc.SourceFile 20 | } 21 | 22 | type ParserContext struct { 23 | ImportedFiles []*token.Token // files and where we imported them from 24 | ExtensionToForbidden map[string]string 25 | Visitors []string 26 | CallbackFn func() 27 | } 28 | 29 | // Simple type that will convey both kinds of context. 30 | type Identifier struct { 31 | Name *token.Token 32 | ParserContext *ParserContext 33 | } 34 | 35 | func NewIdentifier(name Attrib, context interface{}) (*Identifier, error) { 36 | switch pc := context.(type) { 37 | case *ParserContext: 38 | pc.Visitors = append(pc.Visitors, string(name.(*token.Token).Lit)) 39 | if pc.CallbackFn != nil { 40 | pc.CallbackFn() 41 | } 42 | return &Identifier{Name: name.(*token.Token), ParserContext: pc}, nil 43 | 44 | default: 45 | return nil, fmt.Errorf("%s: NewIdentifier expected ParserContext, got %+v", 46 | string(name.(*token.Token).Lit), context) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/usercontext/doc.go: -------------------------------------------------------------------------------- 1 | package example 2 | -------------------------------------------------------------------------------- /example/usercontext/example.bnf: -------------------------------------------------------------------------------- 1 | !whitespace : ' ' | '\r' '\n' | '\n' ; 2 | 3 | lowercase : 'a'-'z' { 'a'-'z' }; 4 | 5 | capitalized : 'A'-'Z' { 'a'-'z' | 'A'-'Z' }; 6 | 7 | << import "github.com/goccmack/gocc/example/usercontext/ast" >> 8 | 9 | // This grammar supports some random number of identifiers (1,N), 10 | // and must be ended with the literal "...42..." 11 | 12 | Grammar 13 | : Words "...42..." << $0, nil >> 14 | ; 15 | 16 | // Capitalized words get no special treatment, lowercase words invoke an ast function 17 | // that expects a valid ParserContext. 18 | Words 19 | : capitalized 20 | | Words capitalized 21 | | lowercase << ast.NewIdentifier($0, $Context) >> 22 | | Words lowercase << ast.NewIdentifier($1, $Context) >> 23 | ; 24 | 25 | -------------------------------------------------------------------------------- /example/usercontext/gen.sh: -------------------------------------------------------------------------------- 1 | gocc -a -p github.com/goccmack/gocc/example/usercontext example.bnf 2 | -------------------------------------------------------------------------------- /example/usercontext/lexer/acttab.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package lexer 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/goccmack/gocc/example/usercontext/token" 9 | ) 10 | 11 | type ActionTable [NumStates]ActionRow 12 | 13 | type ActionRow struct { 14 | Accept token.Type 15 | Ignore string 16 | } 17 | 18 | func (a ActionRow) String() string { 19 | return fmt.Sprintf("Accept=%d, Ignore=%s", a.Accept, a.Ignore) 20 | } 21 | 22 | var ActTab = ActionTable{ 23 | ActionRow{ // S0 24 | Accept: 0, 25 | Ignore: "", 26 | }, 27 | ActionRow{ // S1 28 | Accept: -1, 29 | Ignore: "!whitespace", 30 | }, 31 | ActionRow{ // S2 32 | Accept: 0, 33 | Ignore: "", 34 | }, 35 | ActionRow{ // S3 36 | Accept: 0, 37 | Ignore: "", 38 | }, 39 | ActionRow{ // S4 40 | Accept: 3, 41 | Ignore: "", 42 | }, 43 | ActionRow{ // S5 44 | Accept: 4, 45 | Ignore: "", 46 | }, 47 | ActionRow{ // S6 48 | Accept: 0, 49 | Ignore: "", 50 | }, 51 | ActionRow{ // S7 52 | Accept: 0, 53 | Ignore: "", 54 | }, 55 | ActionRow{ // S8 56 | Accept: 0, 57 | Ignore: "", 58 | }, 59 | ActionRow{ // S9 60 | Accept: 0, 61 | Ignore: "", 62 | }, 63 | ActionRow{ // S10 64 | Accept: 0, 65 | Ignore: "", 66 | }, 67 | ActionRow{ // S11 68 | Accept: 0, 69 | Ignore: "", 70 | }, 71 | ActionRow{ // S12 72 | Accept: 2, 73 | Ignore: "", 74 | }, 75 | } 76 | -------------------------------------------------------------------------------- /example/usercontext/lexer/transitiontable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package lexer 4 | 5 | /* 6 | Let s be the current state 7 | Let r be the current input rune 8 | transitionTable[s](r) returns the next state. 9 | */ 10 | type TransitionTable [NumStates]func(rune) int 11 | 12 | var TransTab = TransitionTable{ 13 | // S0 14 | func(r rune) int { 15 | switch { 16 | case r == 10: // ['\n','\n'] 17 | return 1 18 | case r == 13: // ['\r','\r'] 19 | return 2 20 | case r == 32: // [' ',' '] 21 | return 1 22 | case r == 46: // ['.','.'] 23 | return 3 24 | case 65 <= r && r <= 90: // ['A','Z'] 25 | return 4 26 | case 97 <= r && r <= 122: // ['a','z'] 27 | return 5 28 | } 29 | return NoState 30 | }, 31 | // S1 32 | func(r rune) int { 33 | switch { 34 | } 35 | return NoState 36 | }, 37 | // S2 38 | func(r rune) int { 39 | switch { 40 | case r == 10: // ['\n','\n'] 41 | return 1 42 | } 43 | return NoState 44 | }, 45 | // S3 46 | func(r rune) int { 47 | switch { 48 | case r == 46: // ['.','.'] 49 | return 6 50 | } 51 | return NoState 52 | }, 53 | // S4 54 | func(r rune) int { 55 | switch { 56 | case 65 <= r && r <= 90: // ['A','Z'] 57 | return 4 58 | case 97 <= r && r <= 122: // ['a','z'] 59 | return 4 60 | } 61 | return NoState 62 | }, 63 | // S5 64 | func(r rune) int { 65 | switch { 66 | case 97 <= r && r <= 122: // ['a','z'] 67 | return 5 68 | } 69 | return NoState 70 | }, 71 | // S6 72 | func(r rune) int { 73 | switch { 74 | case r == 46: // ['.','.'] 75 | return 7 76 | } 77 | return NoState 78 | }, 79 | // S7 80 | func(r rune) int { 81 | switch { 82 | case r == 52: // ['4','4'] 83 | return 8 84 | } 85 | return NoState 86 | }, 87 | // S8 88 | func(r rune) int { 89 | switch { 90 | case r == 50: // ['2','2'] 91 | return 9 92 | } 93 | return NoState 94 | }, 95 | // S9 96 | func(r rune) int { 97 | switch { 98 | case r == 46: // ['.','.'] 99 | return 10 100 | } 101 | return NoState 102 | }, 103 | // S10 104 | func(r rune) int { 105 | switch { 106 | case r == 46: // ['.','.'] 107 | return 11 108 | } 109 | return NoState 110 | }, 111 | // S11 112 | func(r rune) int { 113 | switch { 114 | case r == 46: // ['.','.'] 115 | return 12 116 | } 117 | return NoState 118 | }, 119 | // S12 120 | func(r rune) int { 121 | switch { 122 | } 123 | return NoState 124 | }, 125 | } 126 | -------------------------------------------------------------------------------- /example/usercontext/parser/action.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | type action interface { 10 | act() 11 | String() string 12 | } 13 | 14 | type ( 15 | accept bool 16 | shift int // value is next state index 17 | reduce int // value is production index 18 | ) 19 | 20 | func (this accept) act() {} 21 | func (this shift) act() {} 22 | func (this reduce) act() {} 23 | 24 | func (this accept) Equal(that action) bool { 25 | if _, ok := that.(accept); ok { 26 | return true 27 | } 28 | return false 29 | } 30 | 31 | func (this reduce) Equal(that action) bool { 32 | that1, ok := that.(reduce) 33 | if !ok { 34 | return false 35 | } 36 | return this == that1 37 | } 38 | 39 | func (this shift) Equal(that action) bool { 40 | that1, ok := that.(shift) 41 | if !ok { 42 | return false 43 | } 44 | return this == that1 45 | } 46 | 47 | func (this accept) String() string { return "accept(0)" } 48 | func (this shift) String() string { return fmt.Sprintf("shift:%d", this) } 49 | func (this reduce) String() string { 50 | return fmt.Sprintf("reduce:%d(%s)", this, productionsTable[this].String) 51 | } 52 | -------------------------------------------------------------------------------- /example/usercontext/parser/actiontable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | type ( 6 | actionTable [numStates]actionRow 7 | actionRow struct { 8 | canRecover bool 9 | actions [numSymbols]action 10 | } 11 | ) 12 | 13 | var actionTab = actionTable{ 14 | actionRow{ // S0 15 | canRecover: false, 16 | actions: [numSymbols]action{ 17 | nil, // INVALID 18 | nil, // ␚ 19 | nil, // ...42... 20 | shift(3), // capitalized 21 | shift(4), // lowercase 22 | }, 23 | }, 24 | actionRow{ // S1 25 | canRecover: false, 26 | actions: [numSymbols]action{ 27 | nil, // INVALID 28 | accept(true), // ␚ 29 | nil, // ...42... 30 | nil, // capitalized 31 | nil, // lowercase 32 | }, 33 | }, 34 | actionRow{ // S2 35 | canRecover: false, 36 | actions: [numSymbols]action{ 37 | nil, // INVALID 38 | nil, // ␚ 39 | shift(5), // ...42... 40 | shift(6), // capitalized 41 | shift(7), // lowercase 42 | }, 43 | }, 44 | actionRow{ // S3 45 | canRecover: false, 46 | actions: [numSymbols]action{ 47 | nil, // INVALID 48 | nil, // ␚ 49 | reduce(2), // ...42..., reduce: Words 50 | reduce(2), // capitalized, reduce: Words 51 | reduce(2), // lowercase, reduce: Words 52 | }, 53 | }, 54 | actionRow{ // S4 55 | canRecover: false, 56 | actions: [numSymbols]action{ 57 | nil, // INVALID 58 | nil, // ␚ 59 | reduce(4), // ...42..., reduce: Words 60 | reduce(4), // capitalized, reduce: Words 61 | reduce(4), // lowercase, reduce: Words 62 | }, 63 | }, 64 | actionRow{ // S5 65 | canRecover: false, 66 | actions: [numSymbols]action{ 67 | nil, // INVALID 68 | reduce(1), // ␚, reduce: Grammar 69 | nil, // ...42... 70 | nil, // capitalized 71 | nil, // lowercase 72 | }, 73 | }, 74 | actionRow{ // S6 75 | canRecover: false, 76 | actions: [numSymbols]action{ 77 | nil, // INVALID 78 | nil, // ␚ 79 | reduce(3), // ...42..., reduce: Words 80 | reduce(3), // capitalized, reduce: Words 81 | reduce(3), // lowercase, reduce: Words 82 | }, 83 | }, 84 | actionRow{ // S7 85 | canRecover: false, 86 | actions: [numSymbols]action{ 87 | nil, // INVALID 88 | nil, // ␚ 89 | reduce(5), // ...42..., reduce: Words 90 | reduce(5), // capitalized, reduce: Words 91 | reduce(5), // lowercase, reduce: Words 92 | }, 93 | }, 94 | } 95 | -------------------------------------------------------------------------------- /example/usercontext/parser/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | // Parser-specific user-defined and entirely-optional context, 6 | // accessible as '$Context' in SDT actions. 7 | type Context interface{} 8 | -------------------------------------------------------------------------------- /example/usercontext/parser/gototable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | const numNTSymbols = 3 6 | 7 | type ( 8 | gotoTable [numStates]gotoRow 9 | gotoRow [numNTSymbols]int 10 | ) 11 | 12 | var gotoTab = gotoTable{ 13 | gotoRow{ // S0 14 | -1, // S' 15 | 1, // Grammar 16 | 2, // Words 17 | }, 18 | gotoRow{ // S1 19 | -1, // S' 20 | -1, // Grammar 21 | -1, // Words 22 | }, 23 | gotoRow{ // S2 24 | -1, // S' 25 | -1, // Grammar 26 | -1, // Words 27 | }, 28 | gotoRow{ // S3 29 | -1, // S' 30 | -1, // Grammar 31 | -1, // Words 32 | }, 33 | gotoRow{ // S4 34 | -1, // S' 35 | -1, // Grammar 36 | -1, // Words 37 | }, 38 | gotoRow{ // S5 39 | -1, // S' 40 | -1, // Grammar 41 | -1, // Words 42 | }, 43 | gotoRow{ // S6 44 | -1, // S' 45 | -1, // Grammar 46 | -1, // Words 47 | }, 48 | gotoRow{ // S7 49 | -1, // S' 50 | -1, // Grammar 51 | -1, // Words 52 | }, 53 | } 54 | -------------------------------------------------------------------------------- /example/usercontext/parser/productionstable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import "github.com/goccmack/gocc/example/usercontext/ast" 6 | 7 | type ( 8 | ProdTab [numProductions]ProdTabEntry 9 | ProdTabEntry struct { 10 | String string 11 | Id string 12 | NTType int 13 | Index int 14 | NumSymbols int 15 | ReduceFunc func([]Attrib, interface{}) (Attrib, error) 16 | } 17 | Attrib interface { 18 | } 19 | ) 20 | 21 | var productionsTable = ProdTab{ 22 | ProdTabEntry{ 23 | String: `S' : Grammar << >>`, 24 | Id: "S'", 25 | NTType: 0, 26 | Index: 0, 27 | NumSymbols: 1, 28 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 29 | return X[0], nil 30 | }, 31 | }, 32 | ProdTabEntry{ 33 | String: `Grammar : Words "...42..." << X[0], nil >>`, 34 | Id: "Grammar", 35 | NTType: 1, 36 | Index: 1, 37 | NumSymbols: 2, 38 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 39 | return X[0], nil 40 | }, 41 | }, 42 | ProdTabEntry{ 43 | String: `Words : capitalized << >>`, 44 | Id: "Words", 45 | NTType: 2, 46 | Index: 2, 47 | NumSymbols: 1, 48 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 49 | return X[0], nil 50 | }, 51 | }, 52 | ProdTabEntry{ 53 | String: `Words : Words capitalized << >>`, 54 | Id: "Words", 55 | NTType: 2, 56 | Index: 3, 57 | NumSymbols: 2, 58 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 59 | return X[0], nil 60 | }, 61 | }, 62 | ProdTabEntry{ 63 | String: `Words : lowercase << ast.NewIdentifier(X[0], C) >>`, 64 | Id: "Words", 65 | NTType: 2, 66 | Index: 4, 67 | NumSymbols: 1, 68 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 69 | return ast.NewIdentifier(X[0], C) 70 | }, 71 | }, 72 | ProdTabEntry{ 73 | String: `Words : Words lowercase << ast.NewIdentifier(X[1], C) >>`, 74 | Id: "Words", 75 | NTType: 2, 76 | Index: 5, 77 | NumSymbols: 2, 78 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 79 | return ast.NewIdentifier(X[1], C) 80 | }, 81 | }, 82 | } 83 | -------------------------------------------------------------------------------- /example/usercontext/token/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package token 4 | 5 | // Context allows user-defined data to be associated with the 6 | // lexer/scanner to be associated with each token that lexer 7 | // produces. 8 | type Context interface{} 9 | 10 | // Sourcer is a Context interface which presents a Source() method 11 | // identifying e.g the filename for the current code. 12 | type Sourcer interface { 13 | Source() string 14 | } 15 | -------------------------------------------------------------------------------- /example/usercontext/util/rune.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package util 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | func RuneToString(r rune) string { 10 | if r >= 0x20 && r < 0x7f { 11 | return fmt.Sprintf("'%c'", r) 12 | } 13 | switch r { 14 | case 0x07: 15 | return "'\\a'" 16 | case 0x08: 17 | return "'\\b'" 18 | case 0x0C: 19 | return "'\\f'" 20 | case 0x0A: 21 | return "'\\n'" 22 | case 0x0D: 23 | return "'\\r'" 24 | case 0x09: 25 | return "'\\t'" 26 | case 0x0b: 27 | return "'\\v'" 28 | case 0x5c: 29 | return "'\\\\\\'" 30 | case 0x27: 31 | return "'\\''" 32 | case 0x22: 33 | return "'\\\"'" 34 | } 35 | if r < 0x10000 { 36 | return fmt.Sprintf("\\u%04x", r) 37 | } 38 | return fmt.Sprintf("\\U%08x", r) 39 | } 40 | -------------------------------------------------------------------------------- /gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | gocc -o internal/frontend -p "github.com/goccmack/gocc/internal/frontend" spec/gocc2.ebnf 3 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/goccmack/gocc 2 | 3 | go 1.24 4 | 5 | require golang.org/x/mod v0.24.0 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= 2 | golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= 3 | -------------------------------------------------------------------------------- /internal/ast/doc.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /* 16 | This package contains the Abstract Syntax Tree (AST) elements used by gocc to generate a target lexer and parser. 17 | 18 | # The top-level node is Grammar in grammar.go 19 | 20 | The EBNF accepted by gocc consists of two parts: 21 | 22 | 1. The lexical part, containing the definition of tokens. 23 | 24 | 2. The grammar or syntax part, containing the grammar or syntax of the language. Files containing grammar objects are prefixed with "g", e.g.: galts.go 25 | */ 26 | package ast 27 | -------------------------------------------------------------------------------- /internal/ast/fileheader.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/goccmack/gocc/internal/frontend/token" 21 | ) 22 | 23 | type FileHeader struct { 24 | SDTLit string 25 | str string 26 | } 27 | 28 | func NewFileHeader(sdtLit interface{}) (*FileHeader, error) { 29 | sh := &FileHeader{ 30 | SDTLit: sdtLit.(*token.Token).SDTVal(), 31 | } 32 | sh.str = fmt.Sprintf("<< %s >>", sh.SDTLit) 33 | return sh, nil 34 | } 35 | 36 | func (this *FileHeader) String() string { 37 | return this.str 38 | } 39 | -------------------------------------------------------------------------------- /internal/ast/lexalt.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | "strings" 20 | ) 21 | 22 | type LexAlt struct { 23 | Terms []LexTerm 24 | } 25 | 26 | func NewLexAlt(lexTerm interface{}) (*LexAlt, error) { 27 | return &LexAlt{ 28 | Terms: []LexTerm{lexTerm.(LexTerm)}, 29 | }, nil 30 | } 31 | 32 | func AppendLexTerm(lexAlt, lexTerm interface{}) (*LexAlt, error) { 33 | la := lexAlt.(*LexAlt) 34 | la.Terms = append(la.Terms, lexTerm.(LexTerm)) 35 | return la, nil 36 | } 37 | 38 | func (this *LexAlt) Contain(term LexTerm) bool { 39 | for _, thisTerm := range this.Terms { 40 | if thisTerm == term { 41 | return true 42 | } 43 | } 44 | return false 45 | } 46 | 47 | func (this *LexAlt) String() string { 48 | buf := new(strings.Builder) 49 | for i, term := range this.Terms { 50 | if i > 0 { 51 | fmt.Fprintf(buf, " ") 52 | } 53 | fmt.Fprintf(buf, "%s", term.String()) 54 | } 55 | return buf.String() 56 | } 57 | -------------------------------------------------------------------------------- /internal/ast/lexcharlit.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "github.com/goccmack/gocc/internal/frontend/token" 19 | "github.com/goccmack/gocc/internal/util" 20 | ) 21 | 22 | type LexCharLit struct { 23 | Val rune 24 | Lit []byte 25 | s string 26 | } 27 | 28 | func NewLexCharLit(tok interface{}) (*LexCharLit, error) { 29 | return newLexCharLit(tok), nil 30 | } 31 | 32 | func newLexCharLit(tok interface{}) *LexCharLit { 33 | c := new(LexCharLit) 34 | t := tok.(*token.Token) 35 | 36 | c.Val = util.LitToRune(t.Lit) 37 | c.Lit = t.Lit 38 | c.s = util.RuneToString(c.Val) 39 | 40 | return c 41 | } 42 | 43 | func newLexCharLitFromRune(c rune) *LexCharLit { 44 | cl := &LexCharLit{ 45 | Val: c, 46 | s: util.RuneToString(c), 47 | } 48 | cl.Lit = []byte(cl.s) 49 | return cl 50 | } 51 | 52 | func (this *LexCharLit) IsTerminal() bool { 53 | return true 54 | } 55 | func (this *LexCharLit) String() string { 56 | return this.s 57 | } 58 | -------------------------------------------------------------------------------- /internal/ast/lexcharrange.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | ) 20 | 21 | type LexCharRange struct { 22 | From *LexCharLit 23 | To *LexCharLit 24 | s string 25 | } 26 | 27 | func NewLexCharRange(from, to interface{}) (*LexCharRange, error) { 28 | cr := &LexCharRange{ 29 | From: newLexCharLit(from), 30 | To: newLexCharLit(to), 31 | } 32 | 33 | return cr, nil 34 | } 35 | 36 | func (this *LexCharRange) IsTerminal() bool { 37 | return true 38 | } 39 | 40 | func (this *LexCharRange) String() string { 41 | if this.s == "" { 42 | this.s = fmt.Sprintf("%s-%s", this.From.String(), this.To.String()) 43 | } 44 | return this.s 45 | } 46 | -------------------------------------------------------------------------------- /internal/ast/lexdot.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | type LexDot struct{} 18 | 19 | var LexDOT = &LexDot{} 20 | 21 | func (this *LexDot) String() string { 22 | return "." 23 | } 24 | 25 | func (this *LexDot) IsTerminal() bool { 26 | return true 27 | } 28 | -------------------------------------------------------------------------------- /internal/ast/lexgrouppattern.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | "strings" 20 | ) 21 | 22 | type LexGroupPattern struct { 23 | *LexPattern 24 | } 25 | 26 | func NewLexGroupPattern(pattern interface{}) (*LexGroupPattern, error) { 27 | return &LexGroupPattern{pattern.(*LexPattern)}, nil 28 | } 29 | 30 | func (this *LexGroupPattern) IsTerminal() bool { 31 | return false 32 | } 33 | 34 | func (this *LexGroupPattern) String() string { 35 | buf := new(strings.Builder) 36 | fmt.Fprintf(buf, "(%s)", this.LexPattern.String()) 37 | return buf.String() 38 | } 39 | -------------------------------------------------------------------------------- /internal/ast/lexignoredtokdef.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | "strings" 20 | 21 | "github.com/goccmack/gocc/internal/frontend/token" 22 | ) 23 | 24 | type LexIgnoredTokDef struct { 25 | id string 26 | pattern *LexPattern 27 | } 28 | 29 | func NewLexIgnoredTokDef(tokId, lexPattern interface{}) (*LexIgnoredTokDef, error) { 30 | tokDef := &LexIgnoredTokDef{ 31 | id: string(tokId.(*token.Token).Lit), 32 | pattern: lexPattern.(*LexPattern), 33 | } 34 | return tokDef, nil 35 | } 36 | 37 | func (*LexIgnoredTokDef) RegDef() bool { 38 | return false 39 | } 40 | 41 | func (this *LexIgnoredTokDef) String() string { 42 | buf := new(strings.Builder) 43 | fmt.Fprintf(buf, "%s : %s", this.id, this.pattern.String()) 44 | return buf.String() 45 | } 46 | 47 | func (this *LexIgnoredTokDef) Id() string { 48 | return this.id 49 | } 50 | 51 | func (this *LexIgnoredTokDef) LexPattern() *LexPattern { 52 | return this.pattern 53 | } 54 | -------------------------------------------------------------------------------- /internal/ast/leximport.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/goccmack/gocc/internal/frontend/token" 21 | ) 22 | 23 | type LexImport struct { 24 | Id string 25 | ExtFunc string 26 | } 27 | 28 | func NewLexImport(regDefId, extFunc interface{}) (*LexImport, error) { 29 | return &LexImport{ 30 | Id: string(regDefId.(*token.Token).Lit), 31 | ExtFunc: getExtFunc(extFunc), 32 | }, nil 33 | } 34 | 35 | func (this *LexImport) IsTerminal() bool { 36 | return true 37 | } 38 | 39 | func (this *LexImport) String() string { 40 | return fmt.Sprintf("%s \"%s\"", this.Id, this.ExtFunc) 41 | } 42 | 43 | func getExtFunc(strLit interface{}) string { 44 | lit := strLit.(*token.Token).Lit 45 | return string(lit[1 : len(lit)-1]) 46 | } 47 | -------------------------------------------------------------------------------- /internal/ast/leximports.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | "strings" 20 | ) 21 | 22 | type LexImports struct { 23 | Imports map[string]*LexImport 24 | } 25 | 26 | func NewLexImports(lexImport interface{}) (*LexImports, error) { 27 | imports, err := newLexImports().Add(lexImport.(*LexImport)) 28 | return imports, err 29 | } 30 | 31 | func newLexImports() *LexImports { 32 | return &LexImports{ 33 | Imports: make(map[string]*LexImport), 34 | } 35 | } 36 | 37 | func AddLexImport(imports, lexImport interface{}) (*LexImports, error) { 38 | return imports.(*LexImports).Add(lexImport.(*LexImport)) 39 | } 40 | 41 | // Add will return true if a new lex import has been added, otherwise false. 42 | func (this *LexImports) Add(lexImport *LexImport) (*LexImports, error) { 43 | if _, exist := this.Imports[lexImport.Id]; exist { 44 | return nil, fmt.Errorf("duplicate builtin declaration: %s", lexImport.String()) 45 | } 46 | this.Imports[lexImport.Id] = lexImport 47 | return this, nil 48 | } 49 | 50 | func (this *LexImports) String() string { 51 | w := new(strings.Builder) 52 | fmt.Fprintf(w, "import(\n") 53 | for _, imp := range this.Imports { 54 | fmt.Fprintf(w, "\t%s\n", imp.String()) 55 | } 56 | fmt.Fprintf(w, ")") 57 | return w.String() 58 | } 59 | -------------------------------------------------------------------------------- /internal/ast/lexnode.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | type LexNode interface { 18 | LexTerminal() bool 19 | String() string 20 | } 21 | 22 | func (LexAlt) LexTerminal() bool { 23 | return false 24 | } 25 | 26 | func (LexGroupPattern) LexTerminal() bool { 27 | return false 28 | } 29 | 30 | func (*LexIgnoredTokDef) LexTerminal() bool { 31 | return false 32 | } 33 | 34 | func (LexImports) LexTerminal() bool { 35 | return false 36 | } 37 | 38 | func (LexOptPattern) LexTerminal() bool { 39 | return false 40 | } 41 | 42 | func (LexPattern) LexTerminal() bool { 43 | return false 44 | } 45 | 46 | func (LexProductions) LexTerminal() bool { 47 | return false 48 | } 49 | 50 | func (*LexRegDef) LexTerminal() bool { 51 | return false 52 | } 53 | 54 | func (LexRepPattern) LexTerminal() bool { 55 | return false 56 | } 57 | 58 | func (*LexTokDef) LexTerminal() bool { 59 | return false 60 | } 61 | 62 | func (*LexCharLit) LexTerminal() bool { 63 | return true 64 | } 65 | 66 | func (*LexCharRange) LexTerminal() bool { 67 | return true 68 | } 69 | 70 | func (LexDot) LexTerminal() bool { 71 | return true 72 | } 73 | 74 | func (LexRegDefId) LexTerminal() bool { 75 | return true 76 | } 77 | -------------------------------------------------------------------------------- /internal/ast/lexnodevisitor.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | type LexNodeVisitor interface { 18 | Visit(LexNode) LexNodeVisitor 19 | } 20 | -------------------------------------------------------------------------------- /internal/ast/lexntnode.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | type LexNTNode interface { 18 | LexNode 19 | Element(int) LexNode 20 | Len() int 21 | Walk(LexNodeVisitor) LexNodeVisitor 22 | } 23 | 24 | // Element 25 | 26 | func (this *LexAlt) Element(i int) LexNode { 27 | return this.Terms[i] 28 | } 29 | 30 | func (this *LexGroupPattern) Element(i int) LexNode { 31 | return this.LexPattern.Alternatives[i] 32 | } 33 | 34 | func (this *LexOptPattern) Element(i int) LexNode { 35 | return this.LexPattern.Alternatives[i] 36 | } 37 | 38 | func (this *LexPattern) Element(i int) LexNode { 39 | return this.Alternatives[i] 40 | } 41 | 42 | func (this *LexRepPattern) Element(i int) LexNode { 43 | return this.LexPattern.Alternatives[i] 44 | } 45 | 46 | // Len 47 | 48 | func (this *LexAlt) Len() int { 49 | return len(this.Terms) 50 | } 51 | 52 | func (this *LexGroupPattern) Len() int { 53 | return len(this.LexPattern.Alternatives) 54 | } 55 | 56 | func (this *LexOptPattern) Len() int { 57 | return len(this.LexPattern.Alternatives) 58 | } 59 | 60 | func (this *LexPattern) Len() int { 61 | return len(this.Alternatives) 62 | } 63 | 64 | func (this *LexRepPattern) Len() int { 65 | return len(this.LexPattern.Alternatives) 66 | } 67 | -------------------------------------------------------------------------------- /internal/ast/lexoptpattern.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | "strings" 20 | ) 21 | 22 | type LexOptPattern struct { 23 | *LexPattern 24 | } 25 | 26 | func NewLexOptPattern(pattern interface{}) (*LexOptPattern, error) { 27 | return &LexOptPattern{pattern.(*LexPattern)}, nil 28 | } 29 | 30 | func (this *LexOptPattern) IsTerminal() bool { 31 | return false 32 | } 33 | 34 | func (this *LexOptPattern) String() string { 35 | buf := new(strings.Builder) 36 | fmt.Fprintf(buf, "[%s]", this.LexPattern.String()) 37 | return buf.String() 38 | } 39 | -------------------------------------------------------------------------------- /internal/ast/lexpattern.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | "strings" 20 | ) 21 | 22 | type LexPattern struct { 23 | Alternatives []*LexAlt 24 | } 25 | 26 | func NewLexPattern(lexAlt interface{}) (*LexPattern, error) { 27 | return &LexPattern{ 28 | Alternatives: []*LexAlt{lexAlt.(*LexAlt)}, 29 | }, nil 30 | } 31 | 32 | func AppendLexAlt(lexPattern, lexAlt interface{}) (*LexPattern, error) { 33 | lp := lexPattern.(*LexPattern) 34 | lp.Alternatives = append(lp.Alternatives, lexAlt.(*LexAlt)) 35 | return lp, nil 36 | } 37 | 38 | func (this *LexPattern) String() string { 39 | buf := new(strings.Builder) 40 | for i, alt := range this.Alternatives { 41 | if i > 0 { 42 | fmt.Fprintf(buf, " | ") 43 | } 44 | fmt.Fprintf(buf, "%s", alt.String()) 45 | } 46 | return buf.String() 47 | } 48 | -------------------------------------------------------------------------------- /internal/ast/lexprodmap.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | ) 20 | 21 | type LexProdMap struct { 22 | //key: production id 23 | idMap map[string]LexProdIndex 24 | 25 | //value: lex production id 26 | idxMap map[LexProdIndex]string 27 | } 28 | 29 | type LexProdIndex int 30 | 31 | func NewLexProdMap(prodList *LexProductions) *LexProdMap { 32 | lpm := &LexProdMap{ 33 | idMap: make(map[string]LexProdIndex), 34 | idxMap: make(map[LexProdIndex]string), 35 | } 36 | lpm.Add(prodList.Productions...) 37 | 38 | return lpm 39 | } 40 | 41 | func newLexProdMap() *LexProdMap { 42 | return &LexProdMap{ 43 | idMap: make(map[string]LexProdIndex), 44 | idxMap: make(map[LexProdIndex]string), 45 | } 46 | } 47 | 48 | func (this *LexProdMap) Index(id string) LexProdIndex { 49 | idx, exist := this.idMap[id] 50 | if exist { 51 | return idx 52 | } 53 | return -1 54 | } 55 | 56 | func (this *LexProdMap) Id(index LexProdIndex) string { 57 | id, exist := this.idxMap[index] 58 | if exist { 59 | return id 60 | } 61 | return "" 62 | } 63 | 64 | func (this *LexProdMap) Add(prods ...LexProduction) { 65 | for _, prod := range prods { 66 | if _, exist := this.idMap[prod.Id()]; exist { 67 | panic(fmt.Sprintf("Production %s already exists", prod.Id())) 68 | } 69 | idx := len(this.idxMap) 70 | this.idMap[prod.Id()] = LexProdIndex(idx) 71 | this.idxMap[LexProdIndex(idx)] = prod.Id() 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /internal/ast/lexproduction.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | type LexProduction interface { 18 | LexNode 19 | Id() string 20 | LexPattern() *LexPattern 21 | RegDef() bool 22 | } 23 | -------------------------------------------------------------------------------- /internal/ast/lexproductions.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | "strings" 20 | ) 21 | 22 | type LexProductions struct { 23 | Productions []LexProduction 24 | } 25 | 26 | func NewLexProductions(lexProd interface{}) (*LexProductions, error) { 27 | return &LexProductions{ 28 | Productions: []LexProduction{lexProd.(LexProduction)}, 29 | }, nil 30 | } 31 | 32 | func newLexProductions() *LexProductions { 33 | return &LexProductions{ 34 | Productions: []LexProduction{}, 35 | } 36 | } 37 | 38 | func AppendLexProduction(lexProds, prod interface{}) (*LexProductions, error) { 39 | lp := lexProds.(*LexProductions) 40 | lp.Productions = append(lp.Productions, prod.(LexProduction)) 41 | return lp, nil 42 | } 43 | 44 | func (this *LexProductions) String() string { 45 | w := new(strings.Builder) 46 | for _, prod := range this.Productions { 47 | fmt.Fprintf(w, "%s ;", prod.String()) 48 | } 49 | return w.String() 50 | } 51 | -------------------------------------------------------------------------------- /internal/ast/lexregdef.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | "strings" 20 | 21 | "github.com/goccmack/gocc/internal/frontend/token" 22 | ) 23 | 24 | type LexRegDef struct { 25 | id string 26 | pattern *LexPattern 27 | } 28 | 29 | func NewLexRegDef(regDefId, lexPattern interface{}) (*LexRegDef, error) { 30 | regDef := &LexRegDef{ 31 | id: string(regDefId.(*token.Token).Lit), 32 | pattern: lexPattern.(*LexPattern), 33 | } 34 | return regDef, nil 35 | } 36 | 37 | func (*LexRegDef) RegDef() bool { 38 | return true 39 | } 40 | 41 | func (this *LexRegDef) String() string { 42 | buf := new(strings.Builder) 43 | fmt.Fprintf(buf, "%s : %s", this.id, this.pattern.String()) 44 | return buf.String() 45 | } 46 | 47 | func (this *LexRegDef) Id() string { 48 | return this.id 49 | } 50 | 51 | func (this *LexRegDef) LexPattern() *LexPattern { 52 | return this.pattern 53 | } 54 | -------------------------------------------------------------------------------- /internal/ast/lexregdefid.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "github.com/goccmack/gocc/internal/frontend/token" 19 | ) 20 | 21 | type LexRegDefId struct { 22 | Id string 23 | } 24 | 25 | func NewLexRegDefId(regDefId interface{}) (*LexRegDefId, error) { 26 | return &LexRegDefId{ 27 | Id: string(regDefId.(*token.Token).Lit), 28 | }, nil 29 | } 30 | 31 | func (this *LexRegDefId) IsTerminal() bool { 32 | return false 33 | } 34 | 35 | func (this *LexRegDefId) String() string { 36 | return this.Id 37 | } 38 | -------------------------------------------------------------------------------- /internal/ast/lexreppattern.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | "strings" 20 | ) 21 | 22 | type LexRepPattern struct { 23 | *LexPattern 24 | } 25 | 26 | func NewLexRepPattern(pattern interface{}) (*LexRepPattern, error) { 27 | return &LexRepPattern{ 28 | LexPattern: pattern.(*LexPattern), 29 | }, nil 30 | } 31 | 32 | func (this *LexRepPattern) IsTerminal() bool { 33 | return false 34 | } 35 | 36 | func (this *LexRepPattern) String() string { 37 | buf := new(strings.Builder) 38 | fmt.Fprintf(buf, "{%s}", this.LexPattern.String()) 39 | return buf.String() 40 | } 41 | -------------------------------------------------------------------------------- /internal/ast/lexterm.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | type LexTerm interface { 18 | LexNode 19 | 20 | lexTerm() 21 | } 22 | 23 | func (*LexDot) lexTerm() {} 24 | func (*LexCharLit) lexTerm() {} 25 | func (*LexCharRange) lexTerm() {} 26 | func (*LexRegDefId) lexTerm() {} 27 | func (*LexOptPattern) lexTerm() {} 28 | func (*LexRepPattern) lexTerm() {} 29 | func (*LexGroupPattern) lexTerm() {} 30 | -------------------------------------------------------------------------------- /internal/ast/lextnode.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | type LexTNode interface { 18 | LexNode 19 | lexSymbol() 20 | } 21 | 22 | func (*LexCharLit) lexSymbol() {} 23 | func (*LexCharRange) lexSymbol() {} 24 | func (*LexDot) lexSymbol() {} 25 | func (*LexRegDefId) lexSymbol() {} 26 | -------------------------------------------------------------------------------- /internal/ast/lextokdef.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "bytes" 19 | "fmt" 20 | "strings" 21 | 22 | "github.com/goccmack/gocc/internal/frontend/token" 23 | ) 24 | 25 | type LexTokDef struct { 26 | id string 27 | pattern *LexPattern 28 | } 29 | 30 | func NewLexTokDef(tokId, lexPattern interface{}) (*LexTokDef, error) { 31 | tokDef := &LexTokDef{ 32 | id: string(tokId.(*token.Token).Lit), 33 | pattern: lexPattern.(*LexPattern), 34 | } 35 | return tokDef, nil 36 | } 37 | 38 | func NewLexStringLitTokDef(tokId string) *LexTokDef { 39 | runes := bytes.Runes([]byte(tokId)) 40 | alt, _ := NewLexAlt(newLexCharLitFromRune(runes[0])) 41 | for i := 1; i < len(runes); i++ { 42 | alt, _ = AppendLexTerm(alt, newLexCharLitFromRune(runes[i])) 43 | } 44 | ptrn, _ := NewLexPattern(alt) 45 | return &LexTokDef{ 46 | id: tokId, 47 | pattern: ptrn, 48 | } 49 | } 50 | 51 | func (*LexTokDef) RegDef() bool { 52 | return false 53 | } 54 | 55 | func (this *LexTokDef) String() string { 56 | buf := new(strings.Builder) 57 | fmt.Fprintf(buf, "%s : %s", this.id, this.pattern.String()) 58 | return buf.String() 59 | } 60 | 61 | func (this *LexTokDef) Id() string { 62 | return this.id 63 | } 64 | 65 | func (this *LexTokDef) LexPattern() *LexPattern { 66 | return this.pattern 67 | } 68 | -------------------------------------------------------------------------------- /internal/ast/syntaxalts.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | type SyntaxAlts []*SyntaxBody 18 | 19 | func NewSyntaxAlts(body interface{}) (SyntaxAlts, error) { 20 | return SyntaxAlts{body.(*SyntaxBody)}, nil 21 | } 22 | 23 | func AddSyntaxAlt(alts, body interface{}) (SyntaxAlts, error) { 24 | return append(alts.(SyntaxAlts), body.(*SyntaxBody)), nil 25 | } 26 | -------------------------------------------------------------------------------- /internal/ast/syntaxbody.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/goccmack/gocc/internal/frontend/token" 21 | ) 22 | 23 | type SyntaxBody struct { 24 | Error bool 25 | Symbols SyntaxSymbols 26 | SDT string 27 | } 28 | 29 | func NewSyntaxBody(symbols, sdtLit interface{}) (*SyntaxBody, error) { 30 | syntaxBody := &SyntaxBody{ 31 | Error: false, 32 | } 33 | if symbols != nil { 34 | syntaxBody.Symbols = symbols.(SyntaxSymbols) 35 | } 36 | if sdtLit != nil { 37 | syntaxBody.SDT = sdtLit.(*token.Token).SDTVal() 38 | } 39 | return syntaxBody, nil 40 | } 41 | 42 | func NewErrorBody(symbols, sdtLit interface{}) (*SyntaxBody, error) { 43 | body, _ := NewSyntaxBody(symbols, sdtLit) 44 | body.Error = true 45 | return body, nil 46 | } 47 | 48 | func NewEmptyBody() (*SyntaxBody, error) { 49 | return NewSyntaxBody(nil, nil) 50 | } 51 | 52 | func (this *SyntaxBody) Empty() bool { 53 | return len(this.Symbols) == 0 54 | } 55 | 56 | func (this *SyntaxBody) String() string { 57 | return fmt.Sprintf("%s\t<< %s >>", this.Symbols.String(), this.SDT) 58 | } 59 | -------------------------------------------------------------------------------- /internal/ast/syntaxempty.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | type SyntaxEmpty int 18 | 19 | const EMPTY SyntaxEmpty = 0 20 | 21 | func (SyntaxEmpty) SymbolString() string { 22 | return "empty" 23 | } 24 | 25 | func (SyntaxEmpty) String() string { 26 | return "empty" 27 | } 28 | -------------------------------------------------------------------------------- /internal/ast/syntaxeof.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | type SyntaxEof int 18 | 19 | var EOF SyntaxEof = 0 20 | 21 | func (SyntaxEof) SymbolsString() string { 22 | return "␚" 23 | } 24 | 25 | func (SyntaxEof) String() string { 26 | return "␚" 27 | } 28 | -------------------------------------------------------------------------------- /internal/ast/syntaxerror.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | type SyntaxError int 18 | 19 | const errorConst = SyntaxError(-1) 20 | 21 | func (SyntaxError) SymbolString() string { 22 | return "error" 23 | } 24 | 25 | func (SyntaxError) String() string { 26 | return "error" 27 | } 28 | -------------------------------------------------------------------------------- /internal/ast/syntaxpart.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | type SyntaxPart struct { 18 | Header *FileHeader 19 | ProdList SyntaxProdList 20 | } 21 | 22 | func NewSyntaxPart(header, prodList interface{}) (*SyntaxPart, error) { 23 | sp := &SyntaxPart{} 24 | if header != nil { 25 | sp.Header = header.(*FileHeader) 26 | } else { 27 | sp.Header = new(FileHeader) 28 | } 29 | if prodList != nil { 30 | sp.ProdList = prodList.(SyntaxProdList) 31 | } 32 | 33 | return sp, nil 34 | } 35 | 36 | func (this *SyntaxPart) augment() *SyntaxPart { 37 | startProd := &SyntaxProd{ 38 | Id: "S'", 39 | Body: &SyntaxBody{ 40 | Symbols: []SyntaxSymbol{SyntaxProdId(this.ProdList[0].Id)}, 41 | }, 42 | } 43 | newProdList := SyntaxProdList{startProd} 44 | return &SyntaxPart{ 45 | Header: this.Header, 46 | ProdList: append(newProdList, this.ProdList...), 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /internal/ast/syntaxprod.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/goccmack/gocc/internal/frontend/token" 21 | ) 22 | 23 | type SyntaxProd struct { 24 | Id string 25 | Body *SyntaxBody 26 | } 27 | 28 | func NewSyntaxProd(prodId, alts interface{}) ([]*SyntaxProd, error) { 29 | pid := string(prodId.(*token.Token).Lit) 30 | alts1 := alts.(SyntaxAlts) 31 | prods := make([]*SyntaxProd, len(alts1)) 32 | for i, body := range alts1 { 33 | prods[i] = &SyntaxProd{ 34 | Id: pid, 35 | Body: body, 36 | } 37 | } 38 | return prods, nil 39 | } 40 | 41 | func (this *SyntaxProd) String() string { 42 | return fmt.Sprintf("%s : %s", this.Id, this.Body.String()) 43 | } 44 | -------------------------------------------------------------------------------- /internal/ast/syntaxprodid.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "github.com/goccmack/gocc/internal/frontend/token" 19 | ) 20 | 21 | // Id or name of a grammar(syntax) production 22 | type SyntaxProdId string 23 | 24 | func NewSyntaxProdId(tok interface{}) (SyntaxProdId, error) { 25 | return SyntaxProdId(tok.(*token.Token).Lit), nil 26 | } 27 | 28 | func (this SyntaxProdId) SymbolString() string { 29 | return string(this) 30 | } 31 | 32 | func (this SyntaxProdId) String() string { 33 | return string(this) 34 | } 35 | -------------------------------------------------------------------------------- /internal/ast/syntaxprodlist.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | type SyntaxProdList []*SyntaxProd 18 | 19 | func NewSyntaxProdList(prods interface{}) (SyntaxProdList, error) { 20 | return prods.([]*SyntaxProd), nil 21 | } 22 | 23 | func AddSyntaxProds(prodList, prods interface{}) (SyntaxProdList, error) { 24 | return append(prodList.(SyntaxProdList), prods.([]*SyntaxProd)...), nil 25 | } 26 | -------------------------------------------------------------------------------- /internal/ast/syntaxstringlit.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/goccmack/gocc/internal/frontend/token" 21 | ) 22 | 23 | type SyntaxStringLit string 24 | 25 | func NewStringLit(tok interface{}) (SyntaxStringLit, error) { 26 | lit := tok.(*token.Token).Lit 27 | return SyntaxStringLit(lit[1 : len(lit)-1]), nil 28 | } 29 | 30 | func (this SyntaxStringLit) SymbolString() string { 31 | return string(this) 32 | } 33 | 34 | func (this SyntaxStringLit) String() string { 35 | return fmt.Sprintf("\"%s\"", string(this)) 36 | } 37 | 38 | func (this SyntaxStringLit) Bytes() []byte { 39 | return []byte(this) 40 | } 41 | -------------------------------------------------------------------------------- /internal/ast/syntaxsymbol.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | // All syntax symbols are types of string. 18 | type SyntaxSymbol interface { 19 | SymbolString() string 20 | String() string 21 | gSymbol() 22 | } 23 | 24 | func (SyntaxEmpty) gSymbol() {} 25 | func (SyntaxEof) gSymbol() {} 26 | func (SyntaxError) gSymbol() {} 27 | func (SyntaxProdId) gSymbol() {} 28 | func (SyntaxTokId) gSymbol() {} 29 | func (SyntaxStringLit) gSymbol() {} 30 | -------------------------------------------------------------------------------- /internal/ast/syntaxsymbols.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "fmt" 19 | "strings" 20 | ) 21 | 22 | type SyntaxSymbols []SyntaxSymbol 23 | 24 | func NewSyntaxSymbols(sym interface{}) (SyntaxSymbols, error) { 25 | return SyntaxSymbols{sym.(SyntaxSymbol)}, nil 26 | } 27 | 28 | func AddSyntaxSymbol(symbols, symbol interface{}) (SyntaxSymbols, error) { 29 | return append(symbols.(SyntaxSymbols), symbol.(SyntaxSymbol)), nil 30 | } 31 | 32 | func (this SyntaxSymbols) String() string { 33 | w := new(strings.Builder) 34 | for i, sym := range this { 35 | if i > 0 { 36 | fmt.Fprintf(w, " ") 37 | } 38 | fmt.Fprint(w, sym.String()) 39 | } 40 | return w.String() 41 | } 42 | -------------------------------------------------------------------------------- /internal/ast/syntaxtokid.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ast 16 | 17 | import ( 18 | "github.com/goccmack/gocc/internal/frontend/token" 19 | ) 20 | 21 | type SyntaxTokId string 22 | 23 | func NewTokId(tokId interface{}) (SyntaxTokId, error) { 24 | return SyntaxTokId(tokId.(*token.Token).Lit), nil 25 | } 26 | 27 | func (this SyntaxTokId) SymbolString() string { 28 | return string(this) 29 | } 30 | 31 | func (this SyntaxTokId) String() string { 32 | return string(this) 33 | } 34 | -------------------------------------------------------------------------------- /internal/frontend/errors/errors.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import "github.com/goccmack/gocc/internal/frontend/token" 4 | 5 | type ErrorSymbol interface { 6 | } 7 | 8 | type Error struct { 9 | Err error 10 | ErrorToken *token.Token 11 | ErrorPos token.Position 12 | ErrorSymbols []ErrorSymbol 13 | ExpectedTokens []string 14 | } 15 | 16 | func (E *Error) String() string { 17 | errmsg := "Got " + E.ErrorToken.String() + " @ " + E.ErrorPos.String() 18 | if E.Err != nil { 19 | errmsg += " " + E.Err.Error() 20 | } else { 21 | errmsg += ", expected one of: " 22 | for _, t := range E.ExpectedTokens { 23 | errmsg += t + " " 24 | } 25 | } 26 | return errmsg 27 | } 28 | -------------------------------------------------------------------------------- /internal/frontend/scanner/scanner_test.go: -------------------------------------------------------------------------------- 1 | package scanner 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/goccmack/gocc/internal/frontend/token" 8 | ) 9 | 10 | type testRecord struct { 11 | src string 12 | typ token.Type 13 | tokLit string 14 | } 15 | 16 | var testData = []testRecord{ 17 | {"tokId", token.FRONTENDTokens.Type("tokId"), "tokId"}, 18 | {"!whitespace", token.FRONTENDTokens.Type("ignoredTokId"), "!whitespace"}, 19 | {":", token.FRONTENDTokens.Type(":"), ":"}, 20 | {";", token.FRONTENDTokens.Type(";"), ";"}, 21 | {"_regDefId", token.FRONTENDTokens.Type("regDefId"), "_regDefId"}, 22 | {"|", token.FRONTENDTokens.Type("|"), "|"}, 23 | {`'\u0011'`, token.FRONTENDTokens.Type("char_lit"), `'\u0011'`}, 24 | {"-", token.FRONTENDTokens.Type("-"), "-"}, 25 | {"(", token.FRONTENDTokens.Type("("), "("}, 26 | {")", token.FRONTENDTokens.Type(")"), ")"}, 27 | {"[", token.FRONTENDTokens.Type("["), "["}, 28 | {"]", token.FRONTENDTokens.Type("]"), "]"}, 29 | {"{", token.FRONTENDTokens.Type("{"), "{"}, 30 | {"}", token.FRONTENDTokens.Type("}"), "}"}, 31 | {"<< sdt lit >>", token.FRONTENDTokens.Type("g_sdt_lit"), "<< sdt lit >>"}, 32 | {"ProdId", token.FRONTENDTokens.Type("prodId"), "ProdId"}, 33 | {`"string lit"`, token.FRONTENDTokens.Type("string_lit"), `"string lit"`}, 34 | } 35 | 36 | func Test1(tst *testing.T) { 37 | s := &Scanner{} 38 | for _, t := range testData { 39 | s.Init([]byte(t.src), token.FRONTENDTokens) 40 | tok, _ := s.Scan() 41 | if tok.Type != t.typ { 42 | tst.Errorf("src: %s, type: %d -- got type: %d\n", t.src, t.typ, tok.Type) 43 | } 44 | if string(tok.Lit) != t.tokLit { 45 | tst.Errorf("src: %s, expected lit: %s, got: %s\n", t.src, t.tokLit, string(tok.Lit)) 46 | } 47 | } 48 | } 49 | 50 | func Test2(t *testing.T) { 51 | s := &Scanner{} 52 | lit := "The SDT Lit" 53 | s.Init([]byte(fmt.Sprintf("<< %s >>", lit)), token.FRONTENDTokens) 54 | tok, _ := s.Scan() 55 | if tok.Type != token.FRONTENDTokens.Type("g_sdt_lit") { 56 | t.Errorf("Expected tok type: g_sdt_lit, got: %s", token.FRONTENDTokens.TokenString(tok.Type)) 57 | } 58 | if tok.SDTVal() != lit { 59 | t.Errorf("Expected SDTVal: %s, got: %s\n", lit, tok.SDTVal()) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /internal/frontend/token/tokens.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | var FRONTENDTokens = NewMapFromStrings([]string{ 4 | "id", 5 | "tokId", 6 | ":", 7 | ";", 8 | "regDefId", 9 | "ignoredTokId", 10 | "|", 11 | ".", 12 | "char_lit", 13 | "-", 14 | "[", 15 | "]", 16 | "{", 17 | "}", 18 | "(", 19 | ")", 20 | "prodId", 21 | "g_sdt_lit", 22 | "error", 23 | "empty", 24 | "string_lit", 25 | }) 26 | -------------------------------------------------------------------------------- /internal/io/io.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package io 16 | 17 | import ( 18 | "os" 19 | "path" 20 | ) 21 | 22 | const PermDir = 0777 23 | const PermFile = 0666 24 | 25 | func WriteFile(fpath string, data []byte) { 26 | dir, _ := path.Split(fpath) 27 | if err := os.MkdirAll(dir, PermDir); err != nil { 28 | panic(err) 29 | } 30 | if err := os.WriteFile(fpath, data, PermFile); err != nil { 31 | panic(err) 32 | } 33 | } 34 | 35 | func WriteFileString(fpath string, data string) { 36 | WriteFile(fpath, []byte(data)) 37 | } 38 | -------------------------------------------------------------------------------- /internal/lexer/gen/golang/asciitable.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package golang 16 | 17 | import ( 18 | "bytes" 19 | "path" 20 | "text/template" 21 | 22 | "github.com/goccmack/gocc/internal/io" 23 | "github.com/goccmack/gocc/internal/lexer/symbols" 24 | ) 25 | 26 | func genAsciiTable(outDir string, symbols *symbols.Symbols) { 27 | tmpl, err := template.New("ascii table").Parse(asciiTabSrc) 28 | if err != nil { 29 | panic(err) 30 | } 31 | w := new(bytes.Buffer) 32 | if err = tmpl.Execute(w, getAsciiTab(symbols)); err != nil { 33 | panic(err) 34 | } 35 | io.WriteFile(path.Join(outDir, "lexer", "asciitable.go"), w.Bytes()) 36 | } 37 | 38 | func getAsciiTab(symbols *symbols.Symbols) map[rune]asciiType { 39 | asciiMap := make(map[rune]asciiType) 40 | for i, sym := range symbols.List() { 41 | if cl, exist := symbols.CharLitSymbols.GetSymbolId(sym); exist { 42 | if cl.Val < 0x100 { 43 | asciiMap[cl.Val] = asciiType{Type: i, Comment: sym} 44 | } 45 | } 46 | } 47 | return asciiMap 48 | } 49 | 50 | type asciiType struct { 51 | Type int 52 | Comment string 53 | } 54 | 55 | const asciiTabSrc = ` 56 | // Code generated by gocc; DO NOT EDIT. 57 | 58 | package lexer 59 | 60 | const asciiTabLen = 255 61 | 62 | // asciiTable[rune] returns the lexer symbol type of rune 63 | var asciiTable = func() *[asciiTabLen]int { 64 | atab := new([asciiTabLen] int) 65 | for i, _ := range atab { 66 | atab[i] = -1 67 | } 68 | {{range $run, $typ := .}}atab[{{$run}}] = {{$typ.Type}} // {{$typ.Comment}} 69 | {{end}} 70 | return atab 71 | }() 72 | 73 | ` 74 | -------------------------------------------------------------------------------- /internal/lexer/gen/golang/chrranges.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package golang 16 | 17 | import ( 18 | "github.com/goccmack/gocc/internal/lexer/symbols" 19 | ) 20 | 21 | type CharRange struct { 22 | Min, Max rune 23 | Type int 24 | Comment string 25 | } 26 | 27 | func getCharRanges(symbols *symbols.Symbols) (ranges []CharRange) { 28 | ranges = make([]CharRange, symbols.CharRangeSymbols.Len()) 29 | for i, rng := range symbols.CharRangeSymbols.List() { 30 | cr := CharRange{ 31 | Min: rng.From.Val, 32 | Max: rng.To.Val, 33 | Type: symbols.Type(rng.String()), 34 | Comment: rng.String(), 35 | } 36 | ranges[i] = cr 37 | } 38 | return 39 | } 40 | -------------------------------------------------------------------------------- /internal/lexer/gen/golang/gen.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package golang 16 | 17 | import ( 18 | "github.com/goccmack/gocc/internal/config" 19 | "github.com/goccmack/gocc/internal/lexer/items" 20 | "github.com/goccmack/gocc/internal/token" 21 | ) 22 | 23 | func Gen(pkg, outDir string, header string, itemsets *items.ItemSets, tokMap *token.TokenMap, cfg config.Config) { 24 | genLexer(pkg, outDir, itemsets, cfg) 25 | genTransitionTable(pkg, outDir, header, itemsets) 26 | genActionTable(pkg, outDir, itemsets, tokMap) 27 | } 28 | -------------------------------------------------------------------------------- /internal/lexer/gen/golang/imports.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package golang 16 | 17 | import ( 18 | "github.com/goccmack/gocc/internal/lexer/symbols" 19 | ) 20 | 21 | type importType struct { 22 | Id string 23 | ExtFunc string 24 | Type int 25 | } 26 | 27 | func getImports(symbols *symbols.Symbols) (imports []*importType) { 28 | imports = make([]*importType, 0, len(symbols.ImportIdList)) 29 | for _, id := range symbols.ImportIdList { 30 | impType := &importType{ 31 | Id: id, 32 | ExtFunc: symbols.ExternalFunction(id), 33 | Type: symbols.Type(id), 34 | } 35 | imports = append(imports, impType) 36 | } 37 | return 38 | } 39 | -------------------------------------------------------------------------------- /internal/lexer/items/action.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package items 16 | 17 | import ( 18 | "fmt" 19 | ) 20 | 21 | type ( 22 | Action interface { 23 | action() 24 | String() string 25 | } 26 | Accept string 27 | Ignore string 28 | Error int 29 | ) 30 | 31 | func (Accept) action() {} 32 | func (Error) action() {} 33 | func (Ignore) action() {} 34 | 35 | func (this Accept) String() string { 36 | return fmt.Sprintf("Accept(\"%s\")", string(this)) 37 | } 38 | 39 | func (this Ignore) String() string { 40 | return fmt.Sprintf("Ignore(\"%s\")", string(this)) 41 | } 42 | 43 | func (this Error) String() string { 44 | return fmt.Sprintf("Error(%d)", int(this)) 45 | } 46 | -------------------------------------------------------------------------------- /internal/lexer/items/charrange.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package items 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/goccmack/gocc/internal/util" 21 | ) 22 | 23 | type CharRange struct { 24 | From rune 25 | To rune 26 | } 27 | 28 | func (this CharRange) String() string { 29 | return fmt.Sprintf("[%s,%s]", util.RuneToString(this.From), util.RuneToString(this.To)) 30 | } 31 | 32 | func (this CharRange) Equal(that CharRange) bool { 33 | return this.From == that.From && this.To == that.To 34 | } 35 | -------------------------------------------------------------------------------- /internal/lexer/items/itempos_test.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package items 16 | 17 | import ( 18 | // "fmt" 19 | // "github.com/goccmack/gocc/internal/ast" 20 | "testing" 21 | ) 22 | 23 | func TestItemPos1(t *testing.T) { 24 | src := `id : . {.};` 25 | 26 | g := parse(src, t) 27 | prod := g.LexPart.Production("id") 28 | itempos := newItemPos(prod.LexPattern()) 29 | if itempos.level() != 0 { 30 | t.Fatalf("itempos.level() == %d", itempos.level()) 31 | } 32 | if itempos.pos() != 0 { 33 | t.Fatalf("itempos.pos() == %d", itempos.pos()) 34 | } 35 | if itempos.ntNode() != prod.LexPattern() { 36 | t.Fatalf("itempos.ntNode() == %T", itempos.ntNode()) 37 | } 38 | } 39 | 40 | func TestItemPosClone1(t *testing.T) { 41 | src := `id : . {.};` 42 | 43 | g := parse(src, t) 44 | prod := g.LexPart.Production("id") 45 | itempos := newItemPos(prod.LexPattern()) 46 | clone := itempos.clone() 47 | if clone.level() != itempos.level() { 48 | t.Fatalf("clone.level() == %d, itempos.level() == %d", clone.level(), itempos.level()) 49 | } 50 | } 51 | 52 | func TestItemPos2(t *testing.T) { 53 | src := `id : . {.};` 54 | 55 | g := parse(src, t) 56 | prod := g.LexPart.Production("id") 57 | itempos := newItemPos(prod.LexPattern()) 58 | node := prod.LexPattern().Alternatives[0] 59 | itempos.push(node, 0) 60 | if itempos.level() != 1 { 61 | t.Fatalf("itempos.level() == %d", itempos.level()) 62 | } 63 | if itempos.pos() != 0 { 64 | t.Fatalf("itempos.pos() == %d", itempos.pos()) 65 | } 66 | if itempos.ntNode() != node { 67 | t.Fatalf("itempos.ntNode() == %T", itempos.ntNode()) 68 | } 69 | if itempos.level() != 1 { 70 | t.Fatalf("itempos.level() == %d", itempos.level()) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /internal/lexer/items/testutils_test.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package items 16 | 17 | import ( 18 | "testing" 19 | 20 | "github.com/goccmack/gocc/internal/ast" 21 | "github.com/goccmack/gocc/internal/frontend/parser" 22 | "github.com/goccmack/gocc/internal/frontend/scanner" 23 | "github.com/goccmack/gocc/internal/frontend/token" 24 | ) 25 | 26 | func findSet(sets *ItemSets, items []string) *ItemSet { 27 | for _, set := range sets.List() { 28 | if setEqualItems(set, items) { 29 | return set 30 | } 31 | } 32 | return nil 33 | } 34 | 35 | func setEqualItems(set *ItemSet, items []string) bool { 36 | if set.Size() != len(items) { 37 | return false 38 | } 39 | for _, item := range items { 40 | if !setContainItem(set, item) { 41 | return false 42 | } 43 | } 44 | return true 45 | } 46 | 47 | func setContainItem(set *ItemSet, item string) bool { 48 | for _, setItem := range set.Items { 49 | if setItem.str == item { 50 | return true 51 | } 52 | } 53 | return false 54 | } 55 | 56 | func parse(src string, t *testing.T) *ast.Grammar { 57 | scanner := new(scanner.Scanner) 58 | scanner.Init([]byte(src), token.FRONTENDTokens) 59 | parser := parser.NewParser(parser.ActionTable, parser.GotoTable, parser.ProductionsTable, token.FRONTENDTokens) 60 | g, err := parser.Parse(scanner) 61 | if err != nil { 62 | t.Fatalf("Parse error: %s\n", err) 63 | return nil 64 | } 65 | 66 | return g.(*ast.Grammar) 67 | } 68 | -------------------------------------------------------------------------------- /internal/lexer/symbols/charlitsymbols.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package symbols 16 | 17 | import ( 18 | "github.com/goccmack/gocc/internal/ast" 19 | ) 20 | 21 | // key: string of symbols - string(ast.CharLit.Lit). E.g.: "'a'" 22 | type CharLitSymbols struct { 23 | idMap map[string]int 24 | typeMap []*ast.LexCharLit 25 | } 26 | 27 | func NewCharLitSymbols() *CharLitSymbols { 28 | return &CharLitSymbols{ 29 | idMap: make(map[string]int), 30 | typeMap: make([]*ast.LexCharLit, 0, 16), 31 | } 32 | } 33 | 34 | func (this *CharLitSymbols) Add(cl *ast.LexCharLit) { 35 | this.typeMap = append(this.typeMap, cl) 36 | this.idMap[cl.String()] = len(this.typeMap) - 1 37 | } 38 | 39 | func (this *CharLitSymbols) GetSymbolId(id string) (sym *ast.LexCharLit, exist bool) { 40 | if idx, ok := this.idMap[id]; !ok { 41 | return nil, false 42 | } else { 43 | sym = this.typeMap[idx] 44 | } 45 | return 46 | } 47 | 48 | func (this *CharLitSymbols) Len() int { 49 | return len(this.typeMap) 50 | } 51 | 52 | func (this *CharLitSymbols) List() []*ast.LexCharLit { 53 | return this.typeMap 54 | } 55 | 56 | func (this *CharLitSymbols) StringList() []string { 57 | symbols := make([]string, len(this.typeMap)) 58 | for i, sym := range this.typeMap { 59 | symbols[i] = sym.String() 60 | } 61 | return symbols 62 | } 63 | -------------------------------------------------------------------------------- /internal/lexer/symbols/charrangesymbols.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package symbols 16 | 17 | import ( 18 | "github.com/goccmack/gocc/internal/ast" 19 | ) 20 | 21 | // key: string of range, e.g.: 'a'-'z' 22 | type CharRangeSymbols struct { 23 | idmap map[string]int 24 | typeMap []*ast.LexCharRange 25 | } 26 | 27 | func NewCharRangeSymbols() *CharRangeSymbols { 28 | return &CharRangeSymbols{ 29 | idmap: make(map[string]int), 30 | typeMap: make([]*ast.LexCharRange, 0, 16), 31 | } 32 | } 33 | 34 | func (this *CharRangeSymbols) Add(cr *ast.LexCharRange) { 35 | this.typeMap = append(this.typeMap, cr) 36 | this.idmap[cr.String()] = len(this.typeMap) - 1 37 | } 38 | 39 | func (this *CharRangeSymbols) Len() int { 40 | return len(this.typeMap) 41 | } 42 | 43 | func (this *CharRangeSymbols) List() []*ast.LexCharRange { 44 | return this.typeMap 45 | } 46 | 47 | func (this *CharRangeSymbols) StringList() []string { 48 | symbols := make([]string, len(this.typeMap)) 49 | for i, sym := range this.typeMap { 50 | symbols[i] = sym.String() 51 | } 52 | return symbols 53 | } 54 | -------------------------------------------------------------------------------- /internal/parser/first/symbolset.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package first 16 | 17 | import ( 18 | "fmt" 19 | "sort" 20 | "strings" 21 | ) 22 | 23 | /* 24 | key: symbol string 25 | */ 26 | type SymbolSet map[string]bool 27 | 28 | func (this SymbolSet) AddSet(that SymbolSet) { 29 | for id := range that { 30 | this[id] = true 31 | } 32 | } 33 | 34 | func (this SymbolSet) Equal(that SymbolSet) bool { 35 | if len(this) != len(that) { 36 | return false 37 | } 38 | for symbol := range this { 39 | if _, contain := that[symbol]; !contain { 40 | return false 41 | } 42 | } 43 | return true 44 | } 45 | 46 | func (this SymbolSet) String() string { 47 | buf := new(strings.Builder) 48 | fmt.Fprintf(buf, "{\n") 49 | keys := make([]string, 0, len(this)) 50 | for key := range this { 51 | keys = append(keys, key) 52 | } 53 | sort.Strings(keys) 54 | for _, str := range keys { 55 | fmt.Fprintf(buf, "\t%s\n", str) 56 | } 57 | fmt.Fprintf(buf, "}") 58 | return buf.String() 59 | } 60 | -------------------------------------------------------------------------------- /internal/parser/gen/gen.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // This package controls the generation of all parser-related code. 16 | package gen 17 | 18 | import ( 19 | "github.com/goccmack/gocc/internal/ast" 20 | "github.com/goccmack/gocc/internal/config" 21 | "github.com/goccmack/gocc/internal/parser/gen/golang" 22 | "github.com/goccmack/gocc/internal/parser/lr1/items" 23 | "github.com/goccmack/gocc/internal/parser/symbols" 24 | "github.com/goccmack/gocc/internal/token" 25 | ) 26 | 27 | func Gen(pkg, outDir, header string, prods ast.SyntaxProdList, symbols *symbols.Symbols, 28 | itemsets *items.ItemSets, tokMap *token.TokenMap, cfg config.Config) (conflicts map[int]items.RowConflicts) { 29 | golang.GenAction(outDir) 30 | conflicts = golang.GenActionTable(outDir, prods, itemsets, tokMap, cfg.Zip()) 31 | golang.GenContext(pkg, outDir) 32 | golang.GenErrors(pkg, outDir) 33 | golang.GenGotoTable(outDir, itemsets, symbols, cfg.Zip()) 34 | golang.GenParser(pkg, outDir, prods, itemsets, symbols, cfg) 35 | golang.GenProductionsTable(pkg, outDir, header, prods, symbols, itemsets, tokMap) 36 | 37 | return 38 | } 39 | -------------------------------------------------------------------------------- /internal/parser/gen/golang/action.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package golang 16 | 17 | import ( 18 | "path" 19 | 20 | "github.com/goccmack/gocc/internal/io" 21 | ) 22 | 23 | func GenAction(outDir string) { 24 | io.WriteFileString(path.Join(outDir, "parser", "action.go"), actionSrc[1:]) 25 | } 26 | 27 | const actionSrc = ` 28 | // Code generated by gocc; DO NOT EDIT. 29 | 30 | package parser 31 | 32 | import ( 33 | "fmt" 34 | ) 35 | 36 | type action interface { 37 | act() 38 | String() string 39 | } 40 | 41 | type ( 42 | accept bool 43 | shift int // value is next state index 44 | reduce int // value is production index 45 | ) 46 | 47 | func (this accept) act() {} 48 | func (this shift) act() {} 49 | func (this reduce) act() {} 50 | 51 | func (this accept) Equal(that action) bool { 52 | if _, ok := that.(accept); ok { 53 | return true 54 | } 55 | return false 56 | } 57 | 58 | func (this reduce) Equal(that action) bool { 59 | that1, ok := that.(reduce) 60 | if !ok { 61 | return false 62 | } 63 | return this == that1 64 | } 65 | 66 | func (this shift) Equal(that action) bool { 67 | that1, ok := that.(shift) 68 | if !ok { 69 | return false 70 | } 71 | return this == that1 72 | } 73 | 74 | func (this accept) String() string { return "accept(0)" } 75 | func (this shift) String() string { return fmt.Sprintf("shift:%d", this) } 76 | func (this reduce) String() string { 77 | return fmt.Sprintf("reduce:%d(%s)", this, productionsTable[this].String) 78 | } 79 | ` 80 | -------------------------------------------------------------------------------- /internal/parser/gen/golang/context.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package golang 16 | 17 | import ( 18 | "bytes" 19 | "path" 20 | "text/template" 21 | 22 | "github.com/goccmack/gocc/internal/io" 23 | ) 24 | 25 | func GenContext(pkg, outDir string) { 26 | tmpl, err := template.New("context").Parse(contextSrc[1:]) 27 | if err != nil { 28 | panic(err) 29 | } 30 | wr := new(bytes.Buffer) 31 | if err := tmpl.Execute(wr, nil); err != nil { 32 | panic(err) 33 | } 34 | io.WriteFile(path.Join(outDir, "parser", "context.go"), wr.Bytes()) 35 | } 36 | 37 | const contextSrc = ` 38 | // Code generated by gocc; DO NOT EDIT. 39 | 40 | package parser 41 | 42 | // Parser-specific user-defined and entirely-optional context, 43 | // accessible as '$Context' in SDT actions. 44 | type Context interface{} 45 | ` 46 | -------------------------------------------------------------------------------- /internal/parser/lr1/items/rowconflicts.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package items 16 | 17 | import ( 18 | "github.com/goccmack/gocc/internal/parser/lr1/action" 19 | ) 20 | 21 | // key: symbol; value: list of actions. 22 | type RowConflicts map[string][]action.Action 23 | -------------------------------------------------------------------------------- /internal/parser/lr1/items/testdata_test.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package items 16 | 17 | import ( 18 | "testing" 19 | 20 | "github.com/goccmack/gocc/internal/ast" 21 | "github.com/goccmack/gocc/internal/frontend/parser" 22 | "github.com/goccmack/gocc/internal/frontend/scanner" 23 | "github.com/goccmack/gocc/internal/frontend/token" 24 | ) 25 | 26 | const G1 = ` 27 | A : B a ; 28 | 29 | B : b ; 30 | ` 31 | 32 | var G1S0 = []string{ 33 | "A : •B a «$»", 34 | "B : •b «$»", 35 | } 36 | 37 | func parse(src string, t *testing.T) *ast.Grammar { 38 | lexer := new(scanner.Scanner) 39 | lexer.Init([]byte(src), token.FRONTENDTokens) 40 | p := parser.NewParser(parser.ActionTable, parser.GotoTable, parser.ProductionsTable, token.FRONTENDTokens) 41 | res, err := p.Parse(lexer) 42 | if err != nil { 43 | t.Fatal(err) 44 | return nil 45 | } 46 | return res.(*ast.Grammar) 47 | } 48 | -------------------------------------------------------------------------------- /internal/test/Makefile: -------------------------------------------------------------------------------- 1 | regenerate: 2 | make -C t1 regenerate 3 | -------------------------------------------------------------------------------- /internal/test/t1/Makefile: -------------------------------------------------------------------------------- 1 | regenerate: 2 | gocc t1.bnf 3 | -------------------------------------------------------------------------------- /internal/test/t1/doc.go: -------------------------------------------------------------------------------- 1 | package t1 2 | -------------------------------------------------------------------------------- /internal/test/t1/lexer/acttab.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package lexer 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/goccmack/gocc/internal/test/t1/token" 9 | ) 10 | 11 | type ActionTable [NumStates]ActionRow 12 | 13 | type ActionRow struct { 14 | Accept token.Type 15 | Ignore string 16 | } 17 | 18 | func (a ActionRow) String() string { 19 | return fmt.Sprintf("Accept=%d, Ignore=%s", a.Accept, a.Ignore) 20 | } 21 | 22 | var ActTab = ActionTable{ 23 | ActionRow{ // S0 24 | Accept: 0, 25 | Ignore: "", 26 | }, 27 | ActionRow{ // S1 28 | Accept: -1, 29 | Ignore: "!whitespace", 30 | }, 31 | ActionRow{ // S2 32 | Accept: 4, 33 | Ignore: "", 34 | }, 35 | ActionRow{ // S3 36 | Accept: 2, 37 | Ignore: "", 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /internal/test/t1/lexer/transitiontable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package lexer 4 | 5 | /* 6 | Let s be the current state 7 | Let r be the current input rune 8 | transitionTable[s](r) returns the next state. 9 | */ 10 | type TransitionTable [NumStates]func(rune) int 11 | 12 | var TransTab = TransitionTable{ 13 | // S0 14 | func(r rune) int { 15 | switch { 16 | case r == 32: // [' ',' '] 17 | return 1 18 | case r == 98: // ['b','b'] 19 | return 2 20 | case r == 99: // ['c','c'] 21 | return 3 22 | } 23 | return NoState 24 | }, 25 | // S1 26 | func(r rune) int { 27 | switch { 28 | } 29 | return NoState 30 | }, 31 | // S2 32 | func(r rune) int { 33 | switch { 34 | } 35 | return NoState 36 | }, 37 | // S3 38 | func(r rune) int { 39 | switch { 40 | } 41 | return NoState 42 | }, 43 | } 44 | -------------------------------------------------------------------------------- /internal/test/t1/parser/action.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | type action interface { 10 | act() 11 | String() string 12 | } 13 | 14 | type ( 15 | accept bool 16 | shift int // value is next state index 17 | reduce int // value is production index 18 | ) 19 | 20 | func (this accept) act() {} 21 | func (this shift) act() {} 22 | func (this reduce) act() {} 23 | 24 | func (this accept) Equal(that action) bool { 25 | if _, ok := that.(accept); ok { 26 | return true 27 | } 28 | return false 29 | } 30 | 31 | func (this reduce) Equal(that action) bool { 32 | that1, ok := that.(reduce) 33 | if !ok { 34 | return false 35 | } 36 | return this == that1 37 | } 38 | 39 | func (this shift) Equal(that action) bool { 40 | that1, ok := that.(shift) 41 | if !ok { 42 | return false 43 | } 44 | return this == that1 45 | } 46 | 47 | func (this accept) String() string { return "accept(0)" } 48 | func (this shift) String() string { return fmt.Sprintf("shift:%d", this) } 49 | func (this reduce) String() string { 50 | return fmt.Sprintf("reduce:%d(%s)", this, productionsTable[this].String) 51 | } 52 | -------------------------------------------------------------------------------- /internal/test/t1/parser/actiontable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | type ( 6 | actionTable [numStates]actionRow 7 | actionRow struct { 8 | canRecover bool 9 | actions [numSymbols]action 10 | } 11 | ) 12 | 13 | var actionTab = actionTable{ 14 | actionRow{ // S0 15 | canRecover: false, 16 | actions: [numSymbols]action{ 17 | nil, // INVALID 18 | nil, // ␚ 19 | reduce(2), // c, reduce: B 20 | nil, // empty 21 | shift(3), // b 22 | }, 23 | }, 24 | actionRow{ // S1 25 | canRecover: false, 26 | actions: [numSymbols]action{ 27 | nil, // INVALID 28 | accept(true), // ␚ 29 | nil, // c 30 | nil, // empty 31 | nil, // b 32 | }, 33 | }, 34 | actionRow{ // S2 35 | canRecover: false, 36 | actions: [numSymbols]action{ 37 | nil, // INVALID 38 | nil, // ␚ 39 | shift(4), // c 40 | nil, // empty 41 | nil, // b 42 | }, 43 | }, 44 | actionRow{ // S3 45 | canRecover: false, 46 | actions: [numSymbols]action{ 47 | nil, // INVALID 48 | nil, // ␚ 49 | reduce(3), // c, reduce: B 50 | nil, // empty 51 | nil, // b 52 | }, 53 | }, 54 | actionRow{ // S4 55 | canRecover: false, 56 | actions: [numSymbols]action{ 57 | nil, // INVALID 58 | reduce(1), // ␚, reduce: A 59 | nil, // c 60 | nil, // empty 61 | nil, // b 62 | }, 63 | }, 64 | } 65 | -------------------------------------------------------------------------------- /internal/test/t1/parser/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | // Parser-specific user-defined and entirely-optional context, 6 | // accessible as '$Context' in SDT actions. 7 | type Context interface{} 8 | -------------------------------------------------------------------------------- /internal/test/t1/parser/gototable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | const numNTSymbols = 3 6 | 7 | type ( 8 | gotoTable [numStates]gotoRow 9 | gotoRow [numNTSymbols]int 10 | ) 11 | 12 | var gotoTab = gotoTable{ 13 | gotoRow{ // S0 14 | -1, // S' 15 | 1, // A 16 | 2, // B 17 | }, 18 | gotoRow{ // S1 19 | -1, // S' 20 | -1, // A 21 | -1, // B 22 | }, 23 | gotoRow{ // S2 24 | -1, // S' 25 | -1, // A 26 | -1, // B 27 | }, 28 | gotoRow{ // S3 29 | -1, // S' 30 | -1, // A 31 | -1, // B 32 | }, 33 | gotoRow{ // S4 34 | -1, // S' 35 | -1, // A 36 | -1, // B 37 | }, 38 | } 39 | -------------------------------------------------------------------------------- /internal/test/t1/parser/productionstable.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package parser 4 | 5 | type ( 6 | ProdTab [numProductions]ProdTabEntry 7 | ProdTabEntry struct { 8 | String string 9 | Id string 10 | NTType int 11 | Index int 12 | NumSymbols int 13 | ReduceFunc func([]Attrib, interface{}) (Attrib, error) 14 | } 15 | Attrib interface { 16 | } 17 | ) 18 | 19 | var productionsTable = ProdTab{ 20 | ProdTabEntry{ 21 | String: `S' : A << >>`, 22 | Id: "S'", 23 | NTType: 0, 24 | Index: 0, 25 | NumSymbols: 1, 26 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 27 | return X[0], nil 28 | }, 29 | }, 30 | ProdTabEntry{ 31 | String: `A : B "c" << []interface{}{X[0], "c"}, nil >>`, 32 | Id: "A", 33 | NTType: 1, 34 | Index: 1, 35 | NumSymbols: 2, 36 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 37 | return []interface{}{X[0], "c"}, nil 38 | }, 39 | }, 40 | ProdTabEntry{ 41 | String: `B : empty << >>`, 42 | Id: "B", 43 | NTType: 2, 44 | Index: 2, 45 | NumSymbols: 0, 46 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 47 | return nil, nil 48 | }, 49 | }, 50 | ProdTabEntry{ 51 | String: `B : "b" << "b", nil >>`, 52 | Id: "B", 53 | NTType: 2, 54 | Index: 3, 55 | NumSymbols: 1, 56 | ReduceFunc: func(X []Attrib, C interface{}) (Attrib, error) { 57 | return "b", nil 58 | }, 59 | }, 60 | } 61 | -------------------------------------------------------------------------------- /internal/test/t1/t1.bnf: -------------------------------------------------------------------------------- 1 | !whitespace : ' ' ; 2 | 3 | A 4 | : B "c" << []interface{}{$0, "c"}, nil >> 5 | ; 6 | 7 | B 8 | : empty 9 | | "b" << "b", nil >> 10 | ; -------------------------------------------------------------------------------- /internal/test/t1/terminals.txt: -------------------------------------------------------------------------------- 1 | INVALID 2 | $ 3 | c 4 | empty 5 | b 6 | -------------------------------------------------------------------------------- /internal/test/t1/token/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package token 4 | 5 | // Context allows user-defined data to be associated with the 6 | // lexer/scanner to be associated with each token that lexer 7 | // produces. 8 | type Context interface{} 9 | 10 | // Sourcer is a Context interface which presents a Source() method 11 | // identifying e.g the filename for the current code. 12 | type Sourcer interface { 13 | Source() string 14 | } 15 | -------------------------------------------------------------------------------- /internal/test/t1/util/rune.go: -------------------------------------------------------------------------------- 1 | // Code generated by gocc; DO NOT EDIT. 2 | 3 | package util 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | func RuneToString(r rune) string { 10 | if r >= 0x20 && r < 0x7f { 11 | return fmt.Sprintf("'%c'", r) 12 | } 13 | switch r { 14 | case 0x07: 15 | return "'\\a'" 16 | case 0x08: 17 | return "'\\b'" 18 | case 0x0C: 19 | return "'\\f'" 20 | case 0x0A: 21 | return "'\\n'" 22 | case 0x0D: 23 | return "'\\r'" 24 | case 0x09: 25 | return "'\\t'" 26 | case 0x0b: 27 | return "'\\v'" 28 | case 0x5c: 29 | return "'\\\\\\'" 30 | case 0x27: 31 | return "'\\''" 32 | case 0x22: 33 | return "'\\\"'" 34 | } 35 | if r < 0x10000 { 36 | return fmt.Sprintf("\\u%04x", r) 37 | } 38 | return fmt.Sprintf("\\U%08x", r) 39 | } 40 | -------------------------------------------------------------------------------- /internal/test/t2/t2.bnf: -------------------------------------------------------------------------------- 1 | !whitespace : ' ' ; 2 | 3 | A 4 | : B "c" << []interface{}{$0, "c"}, nil >> 5 | ; 6 | 7 | B 8 | : 9 | | "b" << "b", nil >> 10 | ; -------------------------------------------------------------------------------- /internal/test/t2/t2_test.go: -------------------------------------------------------------------------------- 1 | package t2 2 | 3 | import ( 4 | "os/exec" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestEmptyKeyword(t *testing.T) { 10 | var buf = new(strings.Builder) 11 | cmd := exec.Command("gocc", "t2.bnf") 12 | cmd.Stdout = buf 13 | err := cmd.Run() 14 | 15 | e, ok := err.(*exec.ExitError) 16 | if !ok || e.Success() { 17 | t.Fatalf("gocc t2.bnf should return with exit error, but get %v.", err) 18 | } 19 | expectedStderr := `empty production alternative: Maybe you are missing the "empty" keyword in "B : \t<< >>"` 20 | actual := buf.String() 21 | if !strings.Contains(actual, expectedStderr) { 22 | t.Fatalf("%q should contains %q, but not", actual, expectedStderr) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /internal/token/gen/gen.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package gen 16 | 17 | import ( 18 | "github.com/goccmack/gocc/internal/token" 19 | "github.com/goccmack/gocc/internal/token/gen/golang" 20 | ) 21 | 22 | func Gen(pkg, outdir string, tokenMap *token.TokenMap) { 23 | golang.GenToken(pkg, outdir, tokenMap) 24 | golang.GenContext(pkg, outdir) 25 | } 26 | -------------------------------------------------------------------------------- /internal/token/gen/golang/context.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package golang 16 | 17 | import ( 18 | "bytes" 19 | "path" 20 | "text/template" 21 | 22 | "github.com/goccmack/gocc/internal/io" 23 | ) 24 | 25 | func GenContext(pkg, outDir string) { 26 | tmpl, err := template.New("context").Parse(contextSrc[1:]) 27 | if err != nil { 28 | panic(err) 29 | } 30 | wr := new(bytes.Buffer) 31 | if err := tmpl.Execute(wr, nil); err != nil { 32 | panic(err) 33 | } 34 | io.WriteFile(path.Join(outDir, "token", "context.go"), wr.Bytes()) 35 | } 36 | 37 | const contextSrc = ` 38 | // Code generated by gocc; DO NOT EDIT. 39 | 40 | package token 41 | 42 | // Context allows user-defined data to be associated with the 43 | // lexer/scanner to be associated with each token that lexer 44 | // produces. 45 | type Context interface{} 46 | 47 | // Sourcer is a Context interface which presents a Source() method 48 | // identifying e.g the filename for the current code. 49 | type Sourcer interface { 50 | Source() string 51 | } 52 | ` 53 | -------------------------------------------------------------------------------- /internal/token/tokenmap.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package token 16 | 17 | type TokenMap struct { 18 | IdMap map[string]int 19 | TypeMap []string 20 | } 21 | 22 | func NewTokenMap(symbols []string) *TokenMap { 23 | tm := &TokenMap{ 24 | IdMap: make(map[string]int), 25 | TypeMap: make([]string, len(symbols)), 26 | } 27 | 28 | for i, sym := range symbols { 29 | tm.IdMap[sym] = i 30 | tm.TypeMap[i] = sym 31 | } 32 | return tm 33 | } 34 | -------------------------------------------------------------------------------- /internal/util/gen/gen.go: -------------------------------------------------------------------------------- 1 | package gen 2 | 3 | import ( 4 | "github.com/goccmack/gocc/internal/util/gen/golang" 5 | ) 6 | 7 | func Gen(outDir string) { 8 | golang.GenRune(outDir) 9 | golang.GenLitConv(outDir) 10 | } 11 | -------------------------------------------------------------------------------- /internal/util/gen/golang/rune.go: -------------------------------------------------------------------------------- 1 | package golang 2 | 3 | import ( 4 | "path" 5 | 6 | "github.com/goccmack/gocc/internal/io" 7 | ) 8 | 9 | func GenRune(outDir string) { 10 | io.WriteFileString(path.Join(outDir, "util", "rune.go"), runeSrc[1:]) 11 | } 12 | 13 | var runeSrc = ` 14 | // Code generated by gocc; DO NOT EDIT. 15 | 16 | package util 17 | 18 | import ( 19 | "fmt" 20 | ) 21 | 22 | func RuneToString(r rune) string { 23 | if r >= 0x20 && r < 0x7f { 24 | return fmt.Sprintf("'%c'", r) 25 | } 26 | switch r { 27 | case 0x07: 28 | return "'\\a'" 29 | case 0x08: 30 | return "'\\b'" 31 | case 0x0C: 32 | return "'\\f'" 33 | case 0x0A: 34 | return "'\\n'" 35 | case 0x0D: 36 | return "'\\r'" 37 | case 0x09: 38 | return "'\\t'" 39 | case 0x0b: 40 | return "'\\v'" 41 | case 0x5c: 42 | return "'\\\\\\'" 43 | case 0x27: 44 | return "'\\''" 45 | case 0x22: 46 | return "'\\\"'" 47 | } 48 | if r < 0x10000 { 49 | return fmt.Sprintf("\\u%04x", r) 50 | } 51 | return fmt.Sprintf("\\U%08x", r) 52 | } 53 | ` 54 | -------------------------------------------------------------------------------- /internal/util/md/Readme.md: -------------------------------------------------------------------------------- 1 | # Readme 2 | 3 | Package `md` is used to extract the text in code segments of a markdown file. 4 | 5 | Code segments are enclosed in triple backticks: "```", eg: 6 | 7 | ``` 8 | A : B b | c ; 9 | ``` 10 | 11 | `md.GetSource(input string) string` returns a string with the same number of bytes as the input with: 12 | 13 | - All characters inside code segments preserved in place; 14 | - All space characters (`' ', '\n', '\r', '\t'`) outside code segments preserved in place; 15 | - All non-space characters outside code segments replace by `' '` (space). 16 | - The enclosing backticks of code segments replaced with spaces, i.e.: ` "```" ` replaced with `" "`. 17 | -------------------------------------------------------------------------------- /internal/util/md/md.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Marius Ackerman 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /* 16 | Package md extracts code sections of markdown files 17 | */ 18 | package md 19 | 20 | import "os" 21 | 22 | /* 23 | GetSource returns code sections enclosed in triple backticks. 24 | */ 25 | func GetSource(mdfile string) (string, error) { 26 | inbuf, err := os.ReadFile(mdfile) 27 | if err != nil { 28 | return "", err 29 | } 30 | input := []rune(string(inbuf)) 31 | loadMd(input) 32 | return string(input), nil 33 | } 34 | 35 | func loadMd(input []rune) { 36 | i := 0 37 | text := true 38 | for i < len(input) { 39 | if i <= len(input)-3 && input[i] == '`' && input[i+1] == '`' && input[i+2] == '`' { 40 | text = !text 41 | for j := 0; j < 3; j++ { 42 | input[i+j] = ' ' 43 | } 44 | i += 3 45 | } 46 | if i < len(input) { 47 | if text { 48 | if input[i] == '\n' { 49 | input[i] = '\n' 50 | } else { 51 | input[i] = ' ' 52 | } 53 | } 54 | i += 1 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /internal/util/rune.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package util 16 | 17 | import ( 18 | "fmt" 19 | ) 20 | 21 | func RuneToString(r rune) string { 22 | if r >= 0x20 && r < 0x7f { 23 | return fmt.Sprintf("'%c'", r) 24 | } 25 | switch r { 26 | case 0x07: 27 | return "'\\a'" 28 | case 0x08: 29 | return "'\\b'" 30 | case 0x0C: 31 | return "'\\f'" 32 | case 0x0A: 33 | return "'\\n'" 34 | case 0x0D: 35 | return "'\\r'" 36 | case 0x09: 37 | return "'\\t'" 38 | case 0x0b: 39 | return "'\\v'" 40 | case 0x5c: 41 | return "'\\\\\\'" 42 | case 0x27: 43 | return "'\\''" 44 | case 0x22: 45 | return "'\\\"'" 46 | } 47 | if r < 0x10000 { 48 | return fmt.Sprintf("\\u%04x", r) 49 | } 50 | return fmt.Sprintf("\\U%08x", r) 51 | } 52 | -------------------------------------------------------------------------------- /internal/util/stack.go: -------------------------------------------------------------------------------- 1 | //Copyright 2013 Vastech SA (PTY) LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package util 16 | 17 | type Stack struct { 18 | stack []interface{} 19 | } 20 | 21 | // NewStack will return a new, initialized stack. 22 | func NewStack(capacity int) *Stack { 23 | return &Stack{make([]interface{}, 0, capacity)} 24 | } 25 | 26 | // Len returns the number of items on the stack, or 0 if it is empty. 27 | func (this *Stack) Len() int { 28 | return len(this.stack) 29 | } 30 | 31 | // Peek will return the item at `index` in the stack, where 0 is the bottom. Returns 32 | // nil if the index exceeds the length of the stack. 33 | func (this *Stack) Peek(index int) interface{} { 34 | if index > len(this.stack)-1 { 35 | return nil 36 | } 37 | return this.stack[index] 38 | } 39 | 40 | // Pop removes and returns the item at the top of the stack or nil. 41 | func (this *Stack) Pop() (item interface{}) { 42 | if len(this.stack) == 0 { 43 | return nil 44 | } 45 | item = this.stack[len(this.stack)-1] 46 | this.stack = this.stack[:len(this.stack)-1] 47 | return 48 | } 49 | 50 | // Push places an item at the top of the stack or panics if item is nil. 51 | func (this *Stack) Push(items ...interface{}) *Stack { 52 | for _, item := range items { 53 | if item == nil { 54 | panic("nil item may not be pushed") 55 | } 56 | this.stack = append(this.stack, item) 57 | } 58 | return this 59 | } 60 | 61 | // Top returns the item at the top of the stack without altering the stack. 62 | func (this *Stack) Top() interface{} { 63 | return this.stack[len(this.stack)-1] 64 | } 65 | -------------------------------------------------------------------------------- /todo.txt: -------------------------------------------------------------------------------- 1 | Add lexer set action selection algorithm to doc. 2 | 3 | Lexer generation problem: the symbol range of imported function may overlap with the other character ranges and it is impossible during lexer generation to know the overlap. 4 | Do: remove imports 5 | 6 | Symantic checking 7 | Check that user does not use reserved words for ids 8 | 9 | Add error recovery to gocc2 10 | 11 | Clean up visibility of ast fields 12 | 13 | Generate compressed tables. 14 | --------------------------------------------------------------------------------