├── main ├── Makefile └── main.go ├── LICENSE ├── utils.go ├── parse_FSM.go ├── parse_types.go ├── README.md ├── parse_patterns.go ├── ast_defs.go ├── parse_exprs.go ├── parse_stmts.go ├── parser.go ├── lexer.go ├── grammar.txt └── backend_pp.go /main/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | build: 3 | go build -o goParseBSV github.com/rsnikhil/goParseBSV/main 4 | 5 | .PHONY: clean 6 | clean: 7 | rm -f *~ 8 | -------------------------------------------------------------------------------- /main/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Rishiyur Nikhil and Bluespec, Inc. All Rights Reserved. 2 | 3 | package main 4 | 5 | import ( 6 | // golang packages 7 | 8 | // Nikhil's packages 9 | "github.com/rsnikhil/goParseBSV" 10 | ) 11 | 12 | // ================================================================ 13 | 14 | func main () () { 15 | // goParseBSV.TestLexer () 16 | goParseBSV.TestParser () 17 | } 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Rishiyur S. Nikhil 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Rishiyur Nikhil and Bluespec, Inc. All Rights Reserved. 2 | 3 | // Misc. utility functions to classify characters 4 | 5 | package goParseBSV 6 | 7 | import ( 8 | "strings" 9 | ) 10 | 11 | // ================================================================ 12 | // Help functions 13 | 14 | func ByteIsWhitespace (x byte) bool { 15 | return strings.IndexByte (" \n\t\r", x) != -1 16 | } 17 | 18 | func ByteIsLower (x byte) bool { 19 | return ('a' <= x) && (x <= 'z') 20 | } 21 | 22 | func ByteIsUpper (x byte) bool { 23 | return ('A' <= x) && (x <= 'Z') 24 | } 25 | 26 | func ByteIsAlpha (x byte) bool { 27 | return ByteIsLower (x) || ByteIsUpper (x) 28 | } 29 | 30 | func ByteIsDigit (x byte) bool { 31 | return strings.IndexByte ("0123456789", x) != -1 32 | } 33 | 34 | func ByteIsHexdigit (x byte) bool { 35 | return strings.IndexByte ("0123456789ABCDEFabcdef", x) != -1 36 | } 37 | 38 | func ByteIsOctdigit (x byte) bool { 39 | return strings.IndexByte ("012345678", x) != -1 40 | } 41 | 42 | func ByteIsBindigit (x byte) bool { 43 | return strings.IndexByte ("01", x) != -1 44 | } 45 | 46 | // ================================================================ 47 | -------------------------------------------------------------------------------- /parse_FSM.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Rishiyur Nikhil and Bluespec, Inc. All Rights Reserved. 2 | 3 | // Part of goParseBSV, a parser for BSV files 4 | // This part defines parsers for the StmtFSM sub-language 5 | 6 | package goParseBSV 7 | 8 | import ( 9 | // golang packages 10 | "os" 11 | ) 12 | 13 | // ParseFSMstmt parses a FSM statement within a seq, par, if for or while compound 14 | func ParseFSMstmt (lexer *Lexer) (AST) { 15 | debugPrint (os.Stdout, "ParseFSMstmt ...", nil, "\n") 16 | 17 | var result AST 18 | 19 | if skipKeywordOpt (lexer, "seq") { 20 | result = ParseFSMseq (lexer) 21 | 22 | } else if skipKeywordOpt (lexer, "par") { 23 | result = ParseFSMpar (lexer) 24 | 25 | } else if skipKeywordOpt (lexer, "if") { 26 | result = ParseFSMif (lexer) 27 | 28 | } else if skipKeywordOpt (lexer, "for") { 29 | result = ParseFSMfor (lexer) 30 | 31 | } else if skipKeywordOpt (lexer, "while") { 32 | result = ParseFSMwhile (lexer) 33 | 34 | } else if skipKeywordOpt (lexer, "repeat") { 35 | result = ParseFSMrepeat (lexer) 36 | 37 | } else if skipKeywordOpt (lexer, "return") { 38 | result = AstFSMreturn {} 39 | 40 | } else if skipKeywordOpt (lexer, "break") { 41 | result = AstFSMbreak {} 42 | 43 | } else if skipKeywordOpt (lexer, "continue") { 44 | result = AstFSMcontinue {} 45 | 46 | } else { 47 | // Parse an Action expression 48 | result = ParseExpr (lexer) 49 | } 50 | skipPunctuationOpt (lexer, ";") 51 | 52 | debugPrint (os.Stdout, "ParseFSMstmt: => ", result, "\n") 53 | return result 54 | } 55 | 56 | // ParseFSMseq parses: seq ... endseq 57 | // Current token is just past the opening 'seq' 58 | func ParseFSMseq (lexer *Lexer) (* AstFSMseq) { 59 | debugPrint (os.Stdout, "ParseFSMseq ...", nil, "\n") 60 | 61 | var astSeq AstFSMseq 62 | 63 | for { 64 | if skipKeywordOpt (lexer, "endseq") { break } 65 | 66 | astSeq.Stmts = append (astSeq.Stmts, ParseFSMstmt (lexer)) 67 | } 68 | 69 | debugPrint (os.Stdout, "ParseFSMseq: => ", & astSeq, "\n") 70 | return & astSeq 71 | } 72 | 73 | // ParseFSMpar parses: par ... endpar 74 | // Current token is just past the opening 'par' 75 | func ParseFSMpar (lexer *Lexer) (* AstFSMpar) { 76 | debugPrint (os.Stdout, "ParseFSMpar ...", nil, "\n") 77 | 78 | var astPar AstFSMpar 79 | 80 | for { 81 | if skipKeywordOpt (lexer, "endpar") { break } 82 | 83 | astPar.Stmts = append (astPar.Stmts, ParseFSMstmt) 84 | } 85 | 86 | debugPrint (os.Stdout, "ParseFSMpar: => ", & astPar, "\n") 87 | return & astPar 88 | } 89 | 90 | // ParseFSMIf parses: if (E) S1 [ else S2 ] 91 | // Current token is just past 'if' 92 | func ParseFSMif (lexer *Lexer) (*AstFSMif) { 93 | debugPrint (os.Stdout, "ParseFSMif ...", nil, "\n") 94 | 95 | var astFSMif AstFSMif 96 | 97 | // Parse the condition 98 | skipPunctuationMust (lexer, "(") 99 | astFSMif.ExprCond = ParseExpr (lexer) 100 | skipPunctuationMust (lexer, ")") 101 | 102 | // Parse the 'then' part 103 | astFSMif.StmtThen = ParseFSMstmt (lexer) 104 | 105 | // Parse the optional 'else' part 106 | astFSMif.StmtElse = nil 107 | if skipKeywordOpt (lexer, "else") { 108 | astFSMif.StmtElse = ParseFSMstmt (lexer) 109 | } 110 | 111 | result := & astFSMif 112 | debugPrint (os.Stdout, "ParseFSMif: => ", result, "\n") 113 | return result 114 | } 115 | 116 | // ParseFSMfor parses: "for (init; cond; incr) body" 117 | // Current token is just past 'for' 118 | func ParseFSMfor (lexer *Lexer) (* AstFSMfor) { 119 | debugPrint (os.Stdout, "ParseFSMfor ...", nil, "\n") 120 | 121 | var astFor AstFSMfor 122 | 123 | skipPunctuationMust (lexer, "(") 124 | astFor.LoopInit = ParseStmt (lexer) 125 | astFor.LoopCond = ParseExpr (lexer) 126 | skipPunctuationMust (lexer, ";") 127 | astFor.LoopIncr = ParseStmt (lexer) 128 | skipPunctuationMust (lexer, ")") 129 | astFor.LoopBody = ParseFSMstmt (lexer) 130 | 131 | result := & astFor 132 | debugPrint (os.Stdout, "ParseFSMfor: => ", result, "\n") 133 | return result 134 | } 135 | 136 | // ParseFSMwhile parses: "while (cond) body" 137 | // Current token is just past 'while' 138 | func ParseFSMwhile (lexer *Lexer) (* AstFSMwhile) { 139 | debugPrint (os.Stdout, "ParseFSMwhile ...", nil, "\n") 140 | 141 | var astFSMwhile AstFSMwhile 142 | 143 | skipPunctuationMust (lexer, "(") 144 | astFSMwhile.LoopCond = ParseExpr (lexer) 145 | skipPunctuationMust (lexer, ")") 146 | astFSMwhile.LoopBody = ParseFSMstmt (lexer) 147 | 148 | result := & astFSMwhile 149 | debugPrint (os.Stdout, "ParseFSMwhile: => ", result, "\n") 150 | return result 151 | } 152 | 153 | // ParseFSMrepeat parses: "repeat (cond) body" 154 | // Current token is just past 'repeat' 155 | func ParseFSMrepeat (lexer *Lexer) (* AstFSMrepeat) { 156 | debugPrint (os.Stdout, "ParseFSMrepeat ...", nil, "\n") 157 | 158 | var astFSMrepeat AstFSMrepeat 159 | 160 | skipPunctuationMust (lexer, "(") 161 | astFSMrepeat.LoopCount = ParseExpr (lexer) 162 | skipPunctuationMust (lexer, ")") 163 | astFSMrepeat.LoopBody = ParseFSMstmt (lexer) 164 | 165 | result := & astFSMrepeat 166 | debugPrint (os.Stdout, "ParseFSMrepeat: => ", result, "\n") 167 | return result 168 | } 169 | -------------------------------------------------------------------------------- /parse_types.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Rishiyur Nikhil and Bluespec, Inc. All Rights Reserved. 2 | 3 | // Part of goParseBSV, a parser for BSV files 4 | // This part defines parsers for type definitions and type exprs. 5 | 6 | package goParseBSV 7 | 8 | import ( 9 | // golang packages 10 | // -- none -- 11 | ) 12 | 13 | // ================================================================ 14 | // AST parsers 15 | 16 | // ParseTypeExpr parses a complete type expression 17 | // in a typedef or var declaration or assignment. 18 | // (typevar, typenum, constructed, struct) 19 | func ParseTypeExpr (lexer *Lexer) (AST) { 20 | // Not supported: "bit [i:j]" 21 | 22 | if lexer.Token.TokType == TokInteger { 23 | // Numeric type 24 | ast := AstTypeNum {lexer.Token} 25 | GetToken (lexer) 26 | return & ast 27 | 28 | } else if TokenIsIde (lexer) || TokenIsKeyword (lexer, "module") { 29 | // Constructed type 30 | return ParseTypeConstructed (lexer) 31 | } else { 32 | raiseParseError (lexer, "Expecting a type expression\n") 33 | var ast AST 34 | return ast 35 | } 36 | } 37 | 38 | func ParseTypeConstructed (lexer *Lexer) (AST) { 39 | var ast AstTypeConstructed 40 | 41 | // Current token is the identifier for the type 42 | if TokenIsKeyword (lexer, "module") { 43 | ast.Constructor = makeIdeFromToken (*lexer.Token, "module") 44 | GetToken (lexer) 45 | } else { 46 | constructor := ParseIde (lexer) 47 | ast.Constructor = constructor 48 | } 49 | 50 | // Get type args, if any 51 | if skipPunctuationOpt (lexer, "#") { 52 | skipPunctuationMust (lexer, "(") 53 | for { 54 | argAst := ParseTypeExpr (lexer) 55 | ast.Args = append (ast.Args, argAst) 56 | commaFound := skipPunctuationOpt (lexer, ",") 57 | if ! commaFound { 58 | break 59 | } 60 | } 61 | skipPunctuationMust (lexer, ")") 62 | } 63 | return & ast 64 | } 65 | 66 | func ParseTypedefDefinedAsStruct (lexer *Lexer) (AST) { 67 | // Already consumed the "struct" keyword 68 | skipPunctuationMust (lexer, "{") 69 | ast := AstTypedefDefinedAsStruct {} 70 | for { 71 | rbraceFound := skipPunctuationOpt (lexer, "}") 72 | if rbraceFound { break }; 73 | 74 | memberType := ParseTypeExpr (lexer) 75 | memberName := ParseVarIde (lexer) 76 | ast.StructMemberNames = append (ast.StructMemberNames, memberName) 77 | ast.StructMemberTypes = append (ast.StructMemberTypes, memberType) 78 | 79 | if ! TokenIsSpecificPunctuation (lexer, "}") { 80 | skipPunctuationMust (lexer, ";") 81 | } 82 | } 83 | return & ast 84 | } 85 | 86 | func ParseTypedefDefinedAsTaggedUnion (lexer *Lexer) (AST) { 87 | // Already consumed the "union tagged" keyword 88 | skipPunctuationMust (lexer, "{") 89 | ast := AstTypedefDefinedAsTaggedUnion {} 90 | for { 91 | rbraceFound := skipPunctuationOpt (lexer, "}") 92 | if rbraceFound { break }; 93 | 94 | typeExpr := ParseTypeExpr (lexer) 95 | memberName := ParseVarIde (lexer) 96 | ast.TaggedUnionMemberNames = append (ast.TaggedUnionMemberNames, memberName) 97 | ast.TaggedUnionMemberTypes = append (ast.TaggedUnionMemberTypes, typeExpr) 98 | 99 | if ! TokenIsSpecificPunctuation (lexer, "}") { 100 | skipPunctuationMust (lexer, ";") 101 | } 102 | } 103 | return & ast 104 | } 105 | 106 | func ParseTypedefDefinedAsEnum (lexer *Lexer) (AST) { 107 | // Already consumed the "enum" keyword 108 | skipPunctuationMust (lexer, "{") 109 | ast := AstTypedefDefinedAsEnum {} 110 | for { 111 | if skipPunctuationOpt (lexer, "}") { break }; 112 | 113 | typedefEnumElement := ParseConstIde (lexer) 114 | ast.TypedefEnumElements = append (ast.TypedefEnumElements, typedefEnumElement) 115 | var val *AstNum = nil 116 | if skipPunctuationOpt (lexer, "=") { 117 | 118 | if lexer.Token.TokType == TokInteger { 119 | // Integer contant 120 | val = & AstNum {lexer.Token} 121 | GetToken (lexer) 122 | } else { 123 | raiseParseError (lexer, "Expecting a literal integer as enum label value\n") 124 | } 125 | } 126 | ast.TypedefEnumVals = append (ast.TypedefEnumVals, val) 127 | 128 | if ! TokenIsSpecificPunctuation (lexer, "}") { 129 | skipPunctuationMust (lexer, ",") 130 | } 131 | } 132 | return & ast 133 | } 134 | 135 | // ParseTypedefDefinee parses the definee of a BSV typedef: "Constr #(typeformal,...,typeformal)" 136 | // where each typeformal is "type typevar" or "numeric type typevar" 137 | func ParseTypedefDefinee (lexer *Lexer) (*AstTypedefDefinee) { 138 | var ast AstTypedefDefinee 139 | 140 | ast.TypeConstructor = ParseConstIde (lexer) 141 | 142 | formalsFound := skipPunctuationOpt (lexer, "#") 143 | if formalsFound { 144 | skipPunctuationMust (lexer, "(") 145 | for { 146 | rparenFound := skipPunctuationOpt (lexer, ")") 147 | if (rparenFound) { break } 148 | 149 | numeric := skipKeywordOpt (lexer, "numeric") 150 | skipKeywordMust (lexer, "type") 151 | formal := ParseVarIde (lexer) 152 | ast.TypeFormals = append (ast.TypeFormals, formal) 153 | kind := KindValue 154 | if numeric { kind = KindNumeric } 155 | ast.TypeFormalKinds = append (ast.TypeFormalKinds, kind) 156 | 157 | if ! TokenIsSpecificPunctuation (lexer, ")") { 158 | skipPunctuationMust (lexer, ",") 159 | } 160 | } 161 | } 162 | return & ast 163 | } 164 | 165 | // ================================================================ 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # goParseBSV 2 | A standalone parser for BSV (Bluespec SystemVerilog) written in Go 3 | 4 | Copyright (c) 2016-2017 Rishiyur S. Nikhil. All Rights Reserved. 5 | 6 | This is a pure parser, reading in source text file(s) and producing an 7 | AST (Abstract Syntax Tree). The parser is written in the Go 8 | programming language, and has been tested only with Go 1.7.4 under 9 | Linux. 10 | 11 | This parser is intended to enable people to write different back-ends 12 | for BSV, for example to feed into formal verification tools, IDEs, 13 | cross-reference tools, dependency analyzers, etc. 14 | 15 | Caution: It is a fairly substantial task to write an entirely new BSV 16 | compiler (BSV to Verilog) starting with this back end. In addition to 17 | adding remaining front-end tasks (import chasing, type-checking, 18 | static elaboration), one would have to write a "rule scheduler" that 19 | guarantees global rule atomicity. Note that this is a non-local 20 | (non-modular) property, i.e., not restricted to just the module 21 | containing a rule, but reaching through its method calls into 22 | neighboring modules and, transitively through those method calls, into 23 | more remote modules, and even into imported Verilog modules. Further, 24 | this non-modular property is necessary even in the face of separate 25 | compilation. 26 | 27 | ---------------------------------------------------------------- 28 | 29 | ## Example build-and-run 30 | 31 | 32 | Let's assume you have cloned 33 | 34 | github.com/rsnikhil/goParseBSV/ 35 | 36 | into 37 | 38 | $(GOPATH)/github.com/rsnikhil/goParseBSV/ 39 | 40 | In the `goParseBSV/main` directory, do: 41 | 42 | $ make 43 | 44 | This will create an executable `goParseBSV` 45 | 46 | $ ./goParseBSV --help 47 | 48 | will print a help message. 49 | 50 | $ ./goParseBSV --pp Foo.bsv 51 | 52 | will parse the BSV source file Foo.bsv and will either print an error 53 | message if it encounters a syntax error, or a pretty-printed version 54 | of the parse tree for the AST for the whole file. 55 | 56 | $ ./goParseBSV Foo.bsv 57 | 58 | will parse the BSV source file Foo.bsv and just print 'ok' if there are or parse errors. 59 | 60 | ---------------------------------------------------------------- 61 | 62 | ## Status 63 | 64 | It covers most of the BSV language, except: 65 | 66 | * Does not cover `import "BVI"` construct for importing Verilog. 67 | 68 | * Does not cover old-fashioned long-form module instantiation. 69 | 70 | * Does not do preprocessor macro substitution. 71 | 72 | * Does not cover a few other small corner cases. 73 | 74 | All these limitations are likely to be fixed as we continue 75 | development. It does handle `include` and `ifdef macro` constructs, 76 | recursively. 77 | 78 | Note, it's a pure parser and does not do other front-end tasks that 79 | are arguably the job of a subsequent pass over the AST: 80 | 81 | * Does not do any desugaring (other than representing unary prefix and binary infix operators as ordinary function calls) 82 | 83 | * Does not do "import chasing" 84 | 85 | * Does not do scope analysis (proper def-use structure) 86 | * Does not do type-checking 87 | 88 | It has been tested successfully on several dozen real BSV source files 89 | that constitute a small SoC: pipelined CPU, caches, interconnect, 90 | memory system, control fabric, UART model, memory model, etc. 91 | 92 | Still, it is very preliminary. It is not very robust about syntax 93 | errors (a bit too liberal in some places) and is intended for now to 94 | be used only on programs that are acceptable to Bluespec's _bsc_ 95 | compiler; the main purpose is supplementary processing of BSV 96 | programs, not as a front-line parser. It is likely to become more 97 | accurate and exact over time. 98 | 99 | ---------------------------------------------------------------- 100 | 101 | ## Code notes 102 | 103 | `grammar.txt` describes the grammar being parsed. 104 | 105 | `ast_defs.go` describes the ASTs (Abstract Syntax Trees) that are the output of the parser. 106 | 107 | `parser.go` is the top-level file of the parser, and `lexer.go` is the 108 | entire lexical analyzer. The function `TestParser()` at the bottom of 109 | the file shows an example of creating a lexer from an input filename 110 | and a set of macro definitions, and passing it to `ParsePackage()`, 111 | the top-level function that parses a BSV package (in a file), 112 | returning its AST. `TestParser()` also calls `AST_pp()` to pretty-print 113 | the parser. 114 | 115 | Each syntactic construct has a parsing function, and these are grouped 116 | into major syntactic categories in the other files: `parse_types.go`, 117 | `parse_exprs.go`, `parse_patterns.go`, `parse_stmts.go` and 118 | `parse_FSM.go`. 119 | 120 | The parser is a classical, old-fashioned, hand-written, 121 | recursive-descent parser (no parser generators or any such automation). 122 | 123 | `backend_pp.go` is an example back-end: a pretty-printer. You can use 124 | it as a reference for how to traverse an AST when writing new 125 | back-ends for other purposes. 126 | 127 | General tip in understanding the code: Go does not have a 'union' or 128 | 'tagged union' type, to represent alternatives within a syntactic 129 | category. Instead, Go has a concept of an `interface` type on which 130 | one defines interface methods; we use this as a tagged union. The 131 | interface type `AST` is defined in `ast_defs.go` for the purposes of 132 | ASTs. The interface type `ast_pp_ifc` is defined in `backend_pp.go` 133 | for the purposes of the pretty-printer. We expect that each back-end 134 | can do something similar. 135 | -------------------------------------------------------------------------------- /parse_patterns.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Rishiyur Nikhil and Bluespec, Inc. All Rights Reserved. 2 | 3 | // Part of goParseBSV, a parser for BSV files 4 | // This part defines parsers for patterns. 5 | 6 | package goParseBSV 7 | 8 | import ( 9 | // golang packages 10 | "os" 11 | "strconv" 12 | ) 13 | 14 | // ================================================================ 15 | // Parsers 16 | 17 | // ParsePattern is the top-level parser for patterns 18 | func ParsePattern (lexer *Lexer) (AST) { 19 | debugPrint (os.Stdout, "ParsePattern ...", nil, "\n") 20 | 21 | var result AST 22 | 23 | if skipPunctuationOpt (lexer, "(") { 24 | // Parenthesized pattern 25 | result = ParsePattern (lexer) 26 | skipPunctuationMust (lexer, ")") 27 | 28 | } else if TokenIsSpecificPunctuation (lexer, ".") { 29 | // .* or .x (pattern variable) 30 | GetToken (lexer) 31 | if TokenIsSpecificPunctuation (lexer, "*") { 32 | astIde := AstIde { LeafValue: lexer.Token } 33 | GetToken (lexer) 34 | result = & AstPatternVarIde { varIde: & astIde } 35 | } else { 36 | ast := ParseVarIde (lexer) 37 | result = & AstPatternVarIde { varIde: ast } 38 | } 39 | 40 | } else if lexer.Token.TokType == TokInteger { 41 | // Integer contant pattern 42 | ast := AstNum {lexer.Token} 43 | GetToken (lexer) 44 | result = & AstPatternConst { constant: & ast } 45 | 46 | } else if lexer.Token.TokType == TokString { 47 | // String contant pattern 48 | ast := AstString {lexer.Token} 49 | GetToken (lexer) 50 | result = & AstPatternConst { constant: & ast } 51 | 52 | } else if TokenIsKeyword (lexer, "tagged") { 53 | // Tagged union or struct pattern 54 | debugPrint (os.Stdout, "ParsePattern/tagged ...", nil, "\n") 55 | GetToken (lexer) 56 | tag := ParseConstIde (lexer) 57 | if TokenIsSpecificPunctuation (lexer, "{") { 58 | // Struct pattern 59 | result = ParseStructPattern (lexer, tag) 60 | } else { 61 | // Tagged Union pattern 62 | result = ParseTaggedUnionPattern (lexer, tag) 63 | } 64 | 65 | } else if TokenIsSpecificPunctuation (lexer, "{") { 66 | // Tuple pattern 67 | result = ParseTuplePattern (lexer) 68 | 69 | } else if TokenIsIde (lexer) { 70 | // Ide contant pattern (enum label) 71 | ast := AstIde {LeafValue: lexer.Token} 72 | GetToken (lexer) 73 | result = & AstPatternConst { constant: & ast } 74 | 75 | } else { 76 | raiseParseError (lexer, "Expecting a pattern") 77 | } 78 | 79 | debugPrint (os.Stdout, "ParsePattern: => ", result, "\n") 80 | return result 81 | } 82 | 83 | // ParseStructPattern parses a struct pattern; current token is the opening '{' 84 | func ParseStructPattern (lexer *Lexer, structName AST) (AST) { 85 | debugPrint (os.Stdout, "ParseStructPattern ...", nil, "\n") 86 | 87 | var ast AstStructPattern 88 | ast.StructName = structName 89 | debugPrint (os.Stdout, "ParseStructPattern: structName: ", structName, "\n"); 90 | GetToken (lexer) 91 | for { 92 | if TokenIsSpecificPunctuation (lexer, "}") { break } 93 | memberName := ParseVarIde (lexer) 94 | debugPrint (os.Stdout, "ParseStructPattern: memberName: ", memberName, "\n") 95 | ast.MemberNames = append (ast.MemberNames, memberName) 96 | skipPunctuationMust (lexer, ":") 97 | pattern := ParsePattern (lexer) 98 | debugPrint (os.Stdout, "ParseStructPattern: pattern: ", pattern, "\n") 99 | ast.MemberPatterns = append (ast.MemberPatterns, pattern) 100 | if ! TokenIsSpecificPunctuation (lexer, "}") { 101 | skipPunctuationMust (lexer, ",") 102 | } 103 | } 104 | GetToken (lexer) 105 | return & ast 106 | } 107 | 108 | // ParseTuplePattern parses a tuple pattern from the opening '{' 109 | // Tuples are treated as Struct patterns with struct name "{}" 110 | // and member names tuple_1, tuple_2, ... 111 | func ParseTuplePattern (lexer *Lexer) (AST) { 112 | debugPrint (os.Stdout, "ParseTuplePattern ...", nil, "\n") 113 | 114 | var ast AstStructPattern 115 | var tok Token = * lexer.Token 116 | ast.StructName = makeIdeFromToken (tok, "{}") 117 | GetToken (lexer) 118 | var j int = 1 119 | for { 120 | if TokenIsSpecificPunctuation (lexer, "}") { break } 121 | memberName := makeIdeFromToken (tok, "tuple_" + strconv.Itoa (j)) 122 | ast.MemberNames = append (ast.MemberNames, memberName) 123 | pattern := ParsePattern (lexer) 124 | ast.MemberPatterns = append (ast.MemberPatterns, pattern) 125 | if ! TokenIsSpecificPunctuation (lexer, "}") { 126 | skipPunctuationMust (lexer, ",") 127 | } 128 | j += 1 129 | } 130 | GetToken (lexer) 131 | return & ast 132 | } 133 | 134 | // ParseTaggedUnionPattern parses a tagged union pattern: 'tagged tagname pat' 135 | // Current token is first pattern in pat 136 | func ParseTaggedUnionPattern (lexer *Lexer, tag AST) (AST) { 137 | debugPrint (os.Stdout, "ParseTaggedUnionPattern ...", nil, "\n") 138 | 139 | var ast AstTaggedUnionPattern 140 | ast.TaggedUnionName = tag 141 | 142 | // Check if the next token starts a pattern 143 | b1 := TokenIsSpecificPunctuation (lexer, ".") // var, wildcards 144 | b2 := lexer.Token.TokType == TokInteger // const int 145 | b3 := lexer.Token.TokType == TokString // const string 146 | b4 := TokenIsKeyword (lexer, "tagged") // struct/tagged union 147 | b5 := TokenIsSpecificPunctuation (lexer, "{") // tuple 148 | b6 := TokenIsIde (lexer) // const pattern Enum label 149 | b7 := TokenIsSpecificPunctuation (lexer, "(") // parenthesized 150 | if b1 || b2 || b3 || b4 || b5 || b6 || b7 { 151 | ast.MemberPattern = ParsePattern (lexer) 152 | } 153 | return & ast 154 | } 155 | 156 | // ================================================================ 157 | -------------------------------------------------------------------------------- /ast_defs.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Rishiyur Nikhil and Bluespec, Inc. All Rights Reserved. 2 | 3 | // Part of goParseBSV, a parser for BSV files 4 | // This part defines ASTs for BSV 5 | 6 | package goParseBSV 7 | 8 | // ================================================================ 9 | // Each kind of AST has its own struct definition 10 | // They are all 'union'd via the AST interface 11 | // (Go does not seem to have an actual 'union' or 'tagged union' type) 12 | 13 | // AST is the generic type of Abstract Syntax Trees 14 | type AST interface { 15 | } 16 | 17 | // Terminolgy: 18 | // Definee: the thing being defined (classically: Definiendum, cf. Wikipedia) 19 | // DefinedAs: the expression that defines the definee (classically: Definiens, cf. Wikipedia) 20 | 21 | // ================================================================ 22 | // Items that occur in many parts of the grammar 23 | 24 | // Ides 25 | type AstIde struct { 26 | LeafValue *Token // TokIde 27 | } 28 | 29 | // Attribute instances 30 | type AstAttrInstance struct { 31 | Ides [] *AstIde 32 | Vals [] AST 33 | } 34 | 35 | // ================================================================ 36 | // ASTs for types 37 | 38 | // AstTypeNum is a BSV numeric type, e.g., "16" 39 | type AstTypeNum struct { 40 | LeafValue *Token // TokInteger 41 | } 42 | 43 | // AstTypeVar is a BSV type variable (identifier with lowercase first letter) 44 | // E.g., "t" 45 | type AstTypeVar struct { 46 | LeafValue *Token // TokIde 47 | } 48 | 49 | // AstTypeConstructed is a BSV "TypeConstructor #(typeExpr, ..., typeExpr)" 50 | type AstTypeConstructed struct { 51 | Constructor *AstIde 52 | Args [] AST 53 | } 54 | 55 | // AstTypedefDefinedAsStruct is a BSV "struct { type field; ... ; type field }" 56 | type AstTypedefDefinedAsStruct struct { 57 | StructMemberNames [] *AstIde 58 | StructMemberTypes [] AST 59 | } 60 | 61 | // AstTypedefDefinedAsTaggedUnion is a BSV "union tagged { type field; ... ; type field }" 62 | type AstTypedefDefinedAsTaggedUnion struct { 63 | TaggedUnionMemberNames [] *AstIde 64 | TaggedUnionMemberTypes [] AST 65 | } 66 | 67 | // AstTypedefDefinedAsEnum is a BSV "enum { label [=val], ... , label [=val] }" 68 | type AstTypedefDefinedAsEnum struct { 69 | TypedefEnumElements [] *AstIde 70 | TypedefEnumVals [] *AstNum 71 | } 72 | 73 | // Type kinds: either a 'value' type or a 'numeric' type 74 | const ( 75 | KindValue uint = iota 76 | KindNumeric 77 | ) 78 | 79 | // AstTypedefDefinee is the new type being defined in a typedef: Type #(typeFormal,...,typeFormal) 80 | // where each typeformal is "type typevar" or "numeric type typevar" 81 | type AstTypedefDefinee struct { 82 | TypeConstructor *AstIde 83 | TypeFormals [] *AstIde 84 | TypeFormalKinds [] uint 85 | } 86 | 87 | // ================================================================ 88 | // ASTs for exprs 89 | // Integer constant 90 | // Ide 91 | // Expr.identifier // struct field selection, interface method selection 92 | // op Expr // unary prefix operator 93 | // Expr op Expr // binary infix operator 94 | // Expr (Expr, ..., Expr) // function application 95 | // Expr [Expr] // array selection 96 | // (Expr) 97 | // action ... endaction 98 | // begin ... end 99 | // actionvalue ... endactionvalue 100 | // return Expr 101 | // Ide { member:expr, ... } // struct 102 | // interface ... endinterface 103 | 104 | // AstNum is a BSV numeric constant 105 | // E.g., 23 106 | type AstNum struct { 107 | LeafValue *Token // TokInteger 108 | } 109 | 110 | // AstString is a BSV string 111 | // E.g., "x" 112 | type AstString struct { 113 | LeafValue *Token // TokString 114 | } 115 | 116 | // AstExpr is the parse of a BSV expression applying Expr0 to Exprs 117 | type AstExpr struct { 118 | Expr0 AST 119 | Exprs [] AST 120 | } 121 | 122 | // AstCondPredicate is the parse of a condition, in if, while, rule conditions, method conditions, etc. 123 | // i.e., conjunct &&& conjunct &&& ... 124 | type AstCondPredicate struct { 125 | Conjuncts [] AST 126 | } 127 | 128 | // AstCondPattern is the parse of: expr matches pattern 129 | type AstCondPattern struct { 130 | Expr AST 131 | Pattern AST 132 | } 133 | 134 | // AstBlock is the parse of: 135 | // action ... endaction 136 | // actionvalue ... endactionvalue 137 | // begin ... end 138 | type AstBlock struct { 139 | BlockKind string // "action", "actionvalue" or "begin" 140 | BlockName *AstIde 141 | Stmts [] AST 142 | } 143 | 144 | // AstReturn is the parse of: return Expr 145 | type AstReturn struct { 146 | Expr AST 147 | } 148 | 149 | // AstStructExpr is the parse of: Ide {member:Expr, ... } 150 | type AstStructExpr struct { 151 | Name *AstIde 152 | MemberNames [] (*AstIde) 153 | MemberExprs [] AST 154 | } 155 | 156 | // AstTaggedUnionExpr is the parse of: tagged Ide Expr 157 | type AstTaggedUnionExpr struct { 158 | Name *AstIde 159 | Expr AST 160 | } 161 | 162 | // AstCase is the parse of: case ... endcase 163 | type AstCase struct { 164 | Expr AST 165 | Labels [] AST 166 | Exprs [] AST 167 | } 168 | 169 | // AstPatternCase is the parse of: case () matches ... endcase 170 | type AstPatternCase struct { 171 | Expr AST 172 | Patterns [] AST 173 | Exprs [] AST 174 | } 175 | 176 | // AstInterfaceExpr is the parse of expression: interface ... endinterface 177 | type AstInterfaceExpr struct { 178 | Type *AstIde 179 | MethodAndIfcDefs [] AST 180 | } 181 | 182 | // =============================================================== 183 | // ASTs for statements 184 | 185 | // VarDecl is the parse of 'type x1 = e1, x2 = e2, ...;" 186 | type AstVarDecl struct { 187 | Type AST 188 | VarInits [] *AstVarInit 189 | } 190 | 191 | // Kinds of var declarations and assignments 192 | // e.g., "TypeExpr identifier;" 193 | // e.g., "TypeExpr identifier = Expr;" 194 | // e.g., "TypeExpr identifier <- Expr;" 195 | const ( 196 | BindingKindNone uint = iota 197 | BindingKindEq // = 198 | BindingKindLArrow // <- 199 | ) 200 | 201 | // An Init in a VarDecl, 'xJ = eJ' or 'Ide [e]...[e] = Expr;' 202 | type AstVarInit struct { 203 | Ide *AstIde 204 | ArrayDims [] AST 205 | Kind uint 206 | Init AST 207 | } 208 | 209 | // AstLet is the parse of a BSV statement: "let x = e" or "let x <- e" 210 | type AstLet struct { 211 | Ide *AstIde 212 | Kind uint 213 | Expr AST 214 | } 215 | 216 | // AstMatch is the parse of a BSV statement: "match pattern = e" or "match pattern <- e" 217 | type AstMatch struct { 218 | Pattern AST 219 | Expr AST 220 | } 221 | 222 | // AstAssign is the parse of a BSV statement: "lhs = e" or "ide <- e" 223 | type AstAssign struct { 224 | Lhs AST 225 | Kind uint 226 | Rhs AST 227 | } 228 | 229 | // AstRule is the parse of "rule ... endrule" 230 | type AstRule struct { 231 | Name *AstIde 232 | Cond AST 233 | Stmts [] AST 234 | } 235 | 236 | // AstFunctionProto is the parse of "function type name (type formal, ..., type formal)" 237 | type AstFunctionProto struct { 238 | ResultType AST 239 | Name *AstIde 240 | Formals [] AST 241 | FormalTypes [] AST 242 | } 243 | 244 | // AstFunctionDef is the parse of "function ... endfunction" or "function .... = e" 245 | type AstFunctionDef struct { 246 | Proto *AstFunctionProto 247 | Provisos [] AST 248 | Body AST 249 | } 250 | 251 | // AstMethodDef is the parse of "method ... endmethod" or "method .... = e" 252 | type AstMethodDef struct { 253 | ResultType AST 254 | Name *AstIde 255 | Formals [] AST 256 | FormalTypes [] AST 257 | Cond AST 258 | Body AST 259 | } 260 | 261 | // AstModuleDef is the parse of "module ... endmodule" 262 | type AstModuleDef struct { 263 | ModuleType AST 264 | Name *AstIde 265 | FormalParams [] AST 266 | FormalParamTypes [] AST 267 | IfcType AST // TODO: Grammar says this can be a list of ide,type? 268 | Provisos [] AST 269 | Stmts [] AST 270 | } 271 | 272 | // AstInterfaceDef is the parse of "interface ... endinterface" within a module 273 | type AstInterfaceDef struct { 274 | Type AST 275 | Name *AstIde 276 | MethodAndIfcDefs [] AST 277 | } 278 | 279 | // AstInterfaceAssign is the parse of "interface ... = e" within a module 280 | type AstInterfaceAssign struct { 281 | Type AST 282 | Name *AstIde 283 | Val AST 284 | } 285 | 286 | // AstIf is the parse of: "if (E) S1 else S2" 287 | type AstIf struct { 288 | ExprCond AST 289 | StmtThen AST 290 | StmtElse AST 291 | } 292 | 293 | // AstFor is the parse of: "for (type x = e; e; x = ...) stmt" 294 | type AstFor struct { 295 | LoopInit AST 296 | LoopCond AST 297 | LoopIncr AST 298 | LoopBody AST 299 | } 300 | 301 | // AstWhile is the parse of: "while (e) stmt" 302 | type AstWhile struct { 303 | LoopCond AST 304 | LoopBody AST 305 | } 306 | 307 | // ================================================================ 308 | // StmtFSM 309 | 310 | // AstFSMseq is the parse of: 'seq stmt stmt ... endseq' 311 | type AstFSMseq struct { 312 | Stmts [] AST 313 | } 314 | 315 | // AstFSMpar is the parse of: 'par stmt stmt ... endpar' 316 | type AstFSMpar struct { 317 | Stmts [] AST 318 | } 319 | 320 | // AstFSMif is the parse of: 'if (cond) fsmstmt [else fsmstmt]' 321 | type AstFSMif struct { 322 | ExprCond AST 323 | StmtThen AST 324 | StmtElse AST 325 | } 326 | 327 | // AstFSMfor is the parse of: 'for (init_stmts; cond; incr_stmts) fsmstmt' 328 | type AstFSMfor struct { 329 | LoopInit AST 330 | LoopCond AST 331 | LoopIncr AST 332 | LoopBody AST 333 | } 334 | 335 | // AstFSMwhile is the parse of: 'while (cond) fsmstmt' 336 | type AstFSMwhile struct { 337 | LoopCond AST 338 | LoopBody AST 339 | } 340 | 341 | // AstFSMrepeat is the parse of: 'repeat (n) fsmstmt' 342 | type AstFSMrepeat struct { 343 | LoopCount AST 344 | LoopBody AST 345 | } 346 | 347 | // AstFSMreturn is the parse of: 'return' 348 | type AstFSMreturn struct { 349 | } 350 | 351 | // AstFSMbreak is the parse of: 'break' 352 | type AstFSMbreak struct { 353 | } 354 | 355 | // AstFSMcontinue is the parse of: 'continue' 356 | type AstFSMcontinue struct { 357 | } 358 | 359 | // ================================================================ 360 | // ASTs for patterns 361 | // Syntax of patterns: 362 | // Pattern variables 363 | // . * wildcard 364 | // . x pattern varIde 365 | // Pattern constants 366 | // 23 367 | // 2.5 368 | // "Hello" 369 | // Foo enum labels 370 | // Tagged unions 371 | // tagged tag pattern 372 | // Structs 373 | // tagged structname {member:pattern, ...} 374 | // Tuples 375 | // { pattern, ... } 376 | 377 | // AstPatternVarIde is the parse of a pattern .* or .x 378 | type AstPatternVarIde struct { 379 | varIde AST 380 | } 381 | 382 | // AstPatternConst is the parse of a pattern const integer, real, string, or Enum label 383 | type AstPatternConst struct { 384 | constant AST 385 | } 386 | 387 | // AstStructPattern is the parse of: tagged StructName { MemberName: Pattern, ..., } 388 | // and Tuple patterns (StructName is "Tuple", MemberNames are tuple_1, tuple_2, ... 389 | type AstStructPattern struct { 390 | StructName AST 391 | MemberNames [] AST 392 | MemberPatterns [] AST 393 | } 394 | 395 | // AstTaggedUnionPattern is the parse of: tagged UnionName [ Pattern ] 396 | type AstTaggedUnionPattern struct { 397 | TaggedUnionName AST 398 | MemberPattern AST // nil if [ Pattern ] is absent 399 | } 400 | 401 | // ================================================================ 402 | // Top-level constructs in a package 403 | 404 | // AstPackage is parse of 'package pkgStmt ... pkgStmt endpackage' 405 | type AstPackage struct { 406 | PackageName *AstIde 407 | PackageStmts [] AST 408 | } 409 | 410 | // AstImport is parse of 'import x :: *;' 411 | type AstImport struct { 412 | PackageName *AstIde 413 | } 414 | 415 | // AstExport is parse of 'export x, y, z (..), w, ...;' 416 | type AstExport struct { 417 | Ides [] *AstIde 418 | WithMembers [] bool 419 | } 420 | 421 | // AstImportBDPI is parse of 'import "BDPI" function_proto' 422 | type AstImportBDPI struct { 423 | // TODO: C name of the function 424 | Proto *AstFunctionProto 425 | } 426 | 427 | // AstTypedef is the parse of a BSV statement: "typedef typeDefinedAs newtype deriving (typeclass, ...);" 428 | type AstTypedef struct { 429 | TypedefDefinee *AstTypedefDefinee 430 | TypedefDefinedAs AST 431 | TypeclassIdes [] *AstIde 432 | } 433 | 434 | // AstIfcDecl is the parse of a top-level BSV declaration: 'interface ... endinterface' 435 | type AstIfcDecl struct { 436 | Ifc *AstTypedefDefinee 437 | SubIfcOrMethodDecls [] AST 438 | } 439 | 440 | // Sub-interface within an interface declaration 441 | type AstIfcDeclSubIfcDecl struct { 442 | SubIfcName *AstIde 443 | SubIfcType AST 444 | } 445 | 446 | // Method declaration within an interface declaration 447 | type AstIfcDeclMethodDecl struct { 448 | MethodName *AstIde 449 | ReturnType AST 450 | ArgNames [] *AstIde 451 | ArgTypes [] AST 452 | } 453 | 454 | // instance typeclassIde # ( type { , type } ) [ provisos ] ; 455 | // { varAssign ; | functionDef | moduleDef } 456 | // endinstance [ : typeclassIde ] 457 | type AstInstance struct { 458 | TypeclassIde AST 459 | Types [] AST 460 | Provisos [] AST 461 | Stmts [] AST 462 | } 463 | 464 | // ================================================================ 465 | -------------------------------------------------------------------------------- /parse_exprs.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Rishiyur Nikhil and Bluespec, Inc. All Rights Reserved. 2 | 3 | // Part of goParseBSV, a parser for BSV files 4 | // This part defines parsers for exprs. 5 | 6 | package goParseBSV 7 | 8 | import ( 9 | // golang packages 10 | "fmt" 11 | "os" 12 | ) 13 | 14 | // ParseExpr parses a BSV expression 15 | func ParseExpr (lexer *Lexer) (AST) { 16 | debugPrint (os.Stdout, "ParseExpr ...", nil, "\n") 17 | 18 | var result AST 19 | 20 | if TokenIsKeyword (lexer, "return") { 21 | GetToken (lexer) 22 | result = & AstReturn { Expr: ParseCondExpr (lexer) } 23 | } else { 24 | result = ParseCondExpr (lexer) 25 | } 26 | 27 | debugPrint (os.Stdout, "ParseExpr ast: ", result, "\n") 28 | return result 29 | } 30 | 31 | // ParseCondExpr parses a conditional expr: e0 ? e1 : e2 32 | func ParseCondExpr (lexer *Lexer) (AST) { 33 | debugPrint (os.Stdout, "ParseCondExpr ...", nil, "\n") 34 | ast0 := ParseCondPredicate (lexer) 35 | debugPrint (os.Stdout, "ParseCondExpr ast0: ", ast0, "\n") 36 | if TokenIsSpecificPunctuation (lexer, "?") { 37 | var ast AstExpr 38 | ast.Expr0 = makeIdeFromToken (*lexer.Token, "PrimCond") 39 | 40 | GetToken (lexer) 41 | ast1 := ParseCondExpr (lexer) 42 | skipPunctuationMust (lexer, ":") 43 | ast2 := ParseCondExpr (lexer) 44 | 45 | ast.Exprs = [] AST { ast0, ast1, ast2 } 46 | return & ast 47 | } else { 48 | return ast0 49 | } 50 | } 51 | 52 | // ParseCondPredicate parses the predicate of a conditional 53 | func ParseCondPredicate (lexer *Lexer) (AST) { 54 | debugPrint (os.Stdout, "ParseCondPredicate ...", nil, "\n") 55 | 56 | ast := ParseExprOrCondPattern (lexer) 57 | 58 | if TokenIsSpecificPunctuation (lexer, "&&&") { 59 | 60 | var astCP AstCondPredicate 61 | 62 | astCP.Conjuncts = append (astCP.Conjuncts, ast) 63 | 64 | for TokenIsSpecificPunctuation (lexer, "&&&") { 65 | GetToken (lexer) 66 | astJ := ParseExprOrCondPattern (lexer) 67 | astCP.Conjuncts = append (astCP.Conjuncts, astJ) 68 | } 69 | ast = & astCP 70 | } 71 | 72 | debugPrint (os.Stdout, "ParseCondPredicate: => ", ast, "\n") 73 | return ast 74 | } 75 | 76 | // ParseExprOrCondPattern parses an infix binary-op expression 77 | func ParseExprOrCondPattern (lexer *Lexer) (AST) { 78 | debugPrint (os.Stdout, "ParseExprOrCondPattern ...", nil, "\n") 79 | 80 | astExpr := ParseInfixExpr (lexer, 1) 81 | if TokenIsKeyword (lexer, "matches") { 82 | var astCondPattern AstCondPattern 83 | GetToken (lexer) 84 | astCondPattern.Expr = astExpr 85 | astCondPattern.Pattern = ParsePattern (lexer) 86 | debugPrint (os.Stdout, "ParseExprOrCondPattern: => ", & astCondPattern, "\n") 87 | return & astCondPattern 88 | } else { 89 | debugPrint (os.Stdout, "ParseExprOrCondPattern: => ", astExpr, "\n") 90 | return astExpr 91 | } 92 | 93 | } 94 | 95 | // ParseInfixExpr parses an infix binary-op expression 96 | func ParseInfixExpr (lexer *Lexer, precedence int) (AST) { 97 | var astL AST 98 | 99 | debugPrint (os.Stdout, "ParseInfixExpr ...", nil, "\n") 100 | 101 | if (precedence == 11) { 102 | astL = ParseExprUnary (lexer) 103 | } else { 104 | astL = ParseInfixExpr (lexer, precedence + 1) 105 | } 106 | 107 | token := lexer.Token 108 | s := token.StringVal 109 | b := (precedence == 11) && ((s == "*") || (s == "/") || (s == "%")) 110 | b = b || ((precedence == 10) && ((s == "+") || (s == "-"))) 111 | b = b || ((precedence == 9) && ((s == "<<") || (s == ">>"))) 112 | b = b || ((precedence == 8) && ((s == "<=") || (s == ">=") || (s == "<") || (s == ">"))) 113 | b = b || ((precedence == 7) && ((s == "==") || (s == "!="))) 114 | b = b || ((precedence == 6) && (s == "&")) 115 | b = b || ((precedence == 5) && (s == "^")) 116 | b = b || ((precedence == 4) && ((s == "~^") || (s == "^~"))) 117 | b = b || ((precedence == 3) && (s == "|")) 118 | b = b || ((precedence == 2) && (s == "&&")) 119 | b = b || ((precedence == 1) && (s == "||")) 120 | b = (token.TokType == TokOther) && b 121 | 122 | if b { 123 | var ast AstExpr 124 | ast.Expr0 = & (AstIde {LeafValue: token}) 125 | GetToken (lexer) 126 | ast.Exprs = [] AST { astL, ParseInfixExpr (lexer, precedence) } 127 | debugPrint (os.Stdout, "ParseInfixExpr: => ", & ast, "\n") 128 | return & ast 129 | } else { 130 | debugPrint (os.Stdout, "ParseInfixExpr: => ", astL, "\n") 131 | return astL 132 | } 133 | } 134 | 135 | // ParseExprUnary parses a prefix unary-op expression 136 | func ParseExprUnary (lexer *Lexer) (AST) { 137 | debugPrint (os.Stdout, "ParseExprUnary ...", nil, "\n") 138 | token := lexer.Token 139 | s := token.StringVal 140 | isPrefixOp := ((token.TokType == TokOther) && 141 | ((s == "+") || 142 | (s == "-") || 143 | (s == "!") || 144 | (s == "~") || 145 | (s == "&") || 146 | (s == "~&") || 147 | (s == "|") || 148 | (s == "~|") || 149 | (s == "^") || 150 | (s == "^~") || 151 | (s == "~^"))) 152 | if isPrefixOp { 153 | var ast AstExpr 154 | ast.Expr0 = & (AstIde {LeafValue: token}) 155 | GetToken (lexer) 156 | ast.Exprs = [] AST { ParseExprUnary (lexer) } 157 | return & ast 158 | } else { 159 | ast := ParseExprAppOrSelection (lexer) 160 | debugPrint (os.Stdout, "ParseExprUnary: => ", ast, "\n") 161 | return ast 162 | } 163 | } 164 | 165 | // ParseExprAppOrSelection parses an application, member selection, vector selection or bit selection 166 | func ParseExprAppOrSelection (lexer *Lexer) (AST) { 167 | debugPrint (os.Stdout, "ParseExprAppOrSelection ...", nil, "\n") 168 | 169 | ast := ParseExprPrimary (lexer) 170 | 171 | for { 172 | if TokenIsSpecificPunctuation (lexer, ".") { 173 | // Member select 174 | debugPrint (os.Stdout, "ParseExprAppOrSelection. MemberSelect ...", nil, "\n") 175 | 176 | var astExpr AstExpr 177 | astExpr.Expr0 = makeIdeFromToken (* lexer.Token, "PrimMemberSelect") 178 | 179 | GetToken (lexer) 180 | 181 | astExpr.Exprs = [] AST { ast, ParseVarIde (lexer) } 182 | ast = & astExpr 183 | 184 | } else if TokenIsSpecificPunctuation (lexer, "[") { 185 | // Vector or bit selection 186 | debugPrint (os.Stdout, "ParseExprAppOrSelection. [] Select ...", nil, "\n") 187 | 188 | var astExpr AstExpr 189 | tok := *lexer.Token 190 | 191 | GetToken (lexer) 192 | 193 | ast1 := ParseExpr (lexer) 194 | if TokenIsSpecificPunctuation (lexer, ":") { 195 | GetToken (lexer) 196 | ast2 := ParseExpr (lexer) 197 | astExpr.Expr0 = makeIdeFromToken (tok, "PrimBitSelect") 198 | astExpr.Exprs = [] AST { ast, ast1, ast2 } 199 | } else { 200 | astExpr.Expr0 = makeIdeFromToken (tok, "PrimIndex") 201 | astExpr.Exprs = [] AST { ast, ast1 } 202 | } 203 | skipPunctuationMust (lexer, "]") 204 | ast = & astExpr 205 | 206 | } else if TokenIsSpecificPunctuation (lexer, "(") { 207 | // Function call 208 | debugPrint (os.Stdout, "ParseExprAppOrSelection. [] App ...", nil, "\n") 209 | 210 | var astExpr AstExpr 211 | astExpr.Expr0 = makeIdeFromToken (* lexer.Token, "Apply") 212 | astExpr.Exprs = [] AST { ast } 213 | 214 | GetToken (lexer) 215 | for { 216 | if skipPunctuationOpt (lexer, ")") { break } 217 | astJ := ParseExpr (lexer) 218 | astExpr.Exprs = append (astExpr.Exprs, astJ) 219 | if ! TokenIsSpecificPunctuation (lexer, ")") { 220 | skipPunctuationMust (lexer, ",") 221 | } 222 | } 223 | ast = & astExpr 224 | 225 | } else if TokenIsSpecificPunctuation (lexer, "#") { 226 | // This is actually a type expression, a constructed type 227 | // We'll treat it as a value expr for now, convert it later 228 | debugPrint (os.Stdout, "ParseExprAppOrSelection. [] TypeApp ...", nil, "\n") 229 | 230 | var astExpr AstExpr 231 | astExpr.Expr0 = makeIdeFromToken (* lexer.Token, "Apply") 232 | astExpr.Exprs = [] AST { ast } 233 | GetToken (lexer) 234 | skipPunctuationMust (lexer, "(") 235 | 236 | for { 237 | if skipPunctuationOpt (lexer, ")") { break } 238 | astJ := ParseExpr (lexer) 239 | astExpr.Exprs = append (astExpr.Exprs, astJ) 240 | if ! TokenIsSpecificPunctuation (lexer, ")") { 241 | skipPunctuationMust (lexer, ",") 242 | } 243 | } 244 | ast = & astExpr 245 | 246 | } else { 247 | break 248 | } 249 | } 250 | 251 | debugPrint (os.Stdout, "ParseExprAppOrSelection: => ", ast, "\n") 252 | return ast 253 | } 254 | 255 | /* TODO: DELETE? 256 | // ParseExprAppOrSelection parses a function application or selection 257 | func ParseExprApp (lexer *Lexer) (AST) { 258 | debugPrint (os.Stdout, "ParseExprApp ...", nil, "\n") 259 | var ast AST 260 | 261 | ast0 := ParseExprPrimary (lexer) 262 | 263 | if TokenIsSpecificPunctuation (lexer, "(") { 264 | // Function call 265 | var astExpr AstExpr 266 | astExpr.Expr0 = makeIdeFromToken (* lexer.Token, "Apply") 267 | astExpr.Exprs = [] AST { ast0 } 268 | 269 | GetToken (lexer) 270 | for { 271 | if TokenIsSpecificPunctuation (lexer, ")") { break } 272 | astJ := ParseExpr (lexer) 273 | astExpr.Exprs = append (astExpr.Exprs, astJ) 274 | if ! TokenIsSpecificPunctuation (lexer, ")") { 275 | skipPunctuationMust (lexer, ",") 276 | } 277 | } 278 | skipPunctuationMust (lexer, ")") 279 | ast = & astExpr 280 | 281 | } else if TokenIsSpecificPunctuation (lexer, "#") { 282 | // This is actually a type expression, a constructed type 283 | // We'll treat it as a value expr for now, convert it later 284 | var astExpr AstExpr 285 | astExpr.Expr0 = makeIdeFromToken (* lexer.Token, "Apply") 286 | astExpr.Exprs = [] AST { ast0 } 287 | GetToken (lexer) 288 | skipPunctuationMust (lexer, "(") 289 | 290 | for { 291 | if TokenIsSpecificPunctuation (lexer, ")") { break } 292 | astJ := ParseExpr (lexer) 293 | astExpr.Exprs = append (astExpr.Exprs, astJ) 294 | if ! TokenIsSpecificPunctuation (lexer, ")") { 295 | skipPunctuationMust (lexer, ",") 296 | } 297 | } 298 | skipPunctuationMust (lexer, ")") 299 | ast = & astExpr 300 | 301 | } else { 302 | ast = ast0 303 | } 304 | 305 | debugPrint (os.Stdout, "ParseExpr: => ", ast, "\n") 306 | return ast 307 | } 308 | */ 309 | 310 | // ParseExprPrimary parses a basic, non-compound expression 311 | func ParseExprPrimary (lexer *Lexer) (AST) { 312 | debugPrint (os.Stdout, "ParseExprPrimary ...", nil, "\n") 313 | 314 | var result AST 315 | 316 | if lexer.Token.TokType == TokInteger { 317 | // Integer contant 318 | ast := AstNum {lexer.Token} 319 | GetToken (lexer) 320 | result = & ast 321 | 322 | } else if lexer.Token.TokType == TokString { 323 | // String 324 | ast := AstString {lexer.Token} 325 | GetToken (lexer) 326 | result = & ast 327 | 328 | } else if TokenIsKeyword (lexer, "action") { 329 | // actionBlock 330 | result = ParseBlock (lexer, "action") 331 | 332 | } else if TokenIsKeyword (lexer, "actionvalue") { 333 | // actionValueBlock 334 | result = ParseBlock (lexer, "actionvalue") 335 | 336 | } else if TokenIsKeyword (lexer, "begin") { 337 | // actionValueBlock 338 | result = ParseBlock (lexer, "begin") 339 | 340 | } else if skipKeywordOpt (lexer, "interface") { 341 | // interface expression 342 | result = ParseInterfaceExpr (lexer) 343 | 344 | } else if TokenIsKeyword (lexer, "if") { 345 | // case 346 | result = ParseIf (lexer) 347 | 348 | } else if TokenIsKeyword (lexer, "case") { 349 | // case 350 | result = ParseCase (lexer) 351 | 352 | } else if TokenIsKeyword (lexer, "tagged") { 353 | // tagged union expr 354 | GetToken (lexer) 355 | var ast AstTaggedUnionExpr 356 | ast.Name = ParseConstIde (lexer) 357 | // TODO: the following should check for any token that can't begin an Expr 358 | if ! TokenIsSpecificPunctuation (lexer, ";") { 359 | ast.Expr = ParseExpr (lexer) 360 | } 361 | result = & ast 362 | 363 | } else if lexer.Token.TokType == TokIde { 364 | // identifier 365 | astName := AstIde {LeafValue: lexer.Token} 366 | GetToken (lexer) 367 | if TokenIsSpecificPunctuation (lexer, "{") { 368 | // Struct expression 369 | GetToken (lexer) 370 | var astStruct AstStructExpr 371 | astStruct.Name = & astName 372 | for { 373 | if TokenIsSpecificPunctuation (lexer, "}") { break } 374 | astStruct.MemberNames = append (astStruct.MemberNames, ParseVarIde (lexer)) 375 | skipPunctuationMust (lexer, ":") 376 | astStruct.MemberExprs = append (astStruct.MemberExprs, ParseExpr (lexer)) 377 | if ! TokenIsSpecificPunctuation (lexer, "}") { 378 | skipPunctuationMust (lexer, ",") 379 | } 380 | } 381 | skipPunctuationMust (lexer, "}") 382 | result = & astStruct 383 | } else { 384 | result = & astName 385 | } 386 | 387 | } else if TokenIsSpecificPunctuation (lexer, "?") { 388 | // Wildcard ? 389 | ast := AstIde {LeafValue: lexer.Token} 390 | GetToken (lexer) 391 | result = & ast 392 | 393 | } else if TokenIsSpecificPunctuation (lexer, "{") { 394 | // Bit Concat { e1,...,eN} 395 | var ast AstExpr 396 | ast.Expr0 = makeIdeFromToken (* lexer.Token, "PrimBitConcat") 397 | 398 | GetToken (lexer) 399 | for { 400 | if TokenIsSpecificPunctuation (lexer, "}") { break } 401 | astJ := ParseExpr (lexer) 402 | ast.Exprs = append (ast.Exprs, astJ) 403 | if ! TokenIsSpecificPunctuation (lexer, "}") { 404 | skipPunctuationMust (lexer, ",") 405 | } 406 | } 407 | GetToken (lexer) 408 | 409 | result = & ast 410 | 411 | } else if TokenIsSpecificPunctuation (lexer, "(") { 412 | // parenthesized expr 413 | GetToken (lexer) 414 | ast := ParseExpr (lexer) 415 | skipPunctuationMust (lexer, ")") 416 | result = ast 417 | 418 | } else if skipKeywordOpt (lexer, "seq") { 419 | // StmtFSM seq..endseq 420 | result = ParseFSMseq (lexer) 421 | 422 | } else if skipKeywordOpt (lexer, "par") { 423 | // StmtFSM par..endpar 424 | result = ParseFSMpar (lexer) 425 | 426 | } else { 427 | raiseParseError (lexer, "Expecting a basic, non-compound expression\n") 428 | var ast AST 429 | result = ast 430 | } 431 | debugPrint (os.Stdout, "ParseExprPrimary: => ", result, "\n") 432 | return result 433 | } 434 | 435 | // ParseBlock parses: action ... endaction, actionvalue ... endactionvalue and begin ... end 436 | // Current token is 'action'/'actionvalue'/'begin' 437 | func ParseBlock (lexer *Lexer, kind string) (AST) { 438 | debugPrint (os.Stdout, "ParseBlock ...", nil, "\n") 439 | 440 | var ast AstBlock 441 | ast.BlockKind = kind 442 | 443 | // Skip 'action'/'actionvalue' keyword 444 | GetToken (lexer) 445 | 446 | // Get the optional block name 447 | if TokenIsSpecificPunctuation (lexer, ":") { 448 | GetToken (lexer) 449 | ast.BlockName = ParseVarIde (lexer) 450 | } 451 | 452 | ast.Stmts = ParseStmts (lexer) 453 | 454 | // Parse the 'endaction'/'endactionvalue' keyword 455 | endkeyword := MatchingEndKeyword (kind) 456 | if ! TokenIsKeyword (lexer, endkeyword) { 457 | raiseParseError (lexer, fmt.Sprintf ("Expecting '%s'\n", endkeyword)) 458 | } 459 | GetToken (lexer) 460 | 461 | // Get the optional block name 462 | if TokenIsSpecificPunctuation (lexer, ":") { 463 | GetToken (lexer) 464 | end_blockName := ParseVarIde (lexer) 465 | // TODO: use SameIde predicate here, not != 466 | if ast.BlockName != end_blockName { 467 | raiseParseError (lexer, "Mismatched block names after 'action' and 'endaction'\n") 468 | } 469 | } 470 | 471 | debugPrint (os.Stdout, "ParseBlock: => ", & ast, "\n") 472 | return & ast 473 | } 474 | 475 | // ParseIf parses: if (E) S1 [ else S2 ] 476 | // Current token is 'if' 477 | func ParseIf (lexer *Lexer) (AST) { 478 | debugPrint (os.Stdout, "ParseIf ...", nil, "\n") 479 | 480 | var astIf AstIf 481 | 482 | // Skip 'if' keyword 483 | GetToken (lexer) 484 | skipPunctuationMust (lexer, "(") 485 | astIf.ExprCond = ParseExpr (lexer) 486 | skipPunctuationMust (lexer, ")") 487 | astIf.StmtThen = ParseStmt (lexer) 488 | 489 | astIf.StmtElse = nil 490 | if skipKeywordOpt (lexer, "else") { 491 | astIf.StmtElse = ParseStmt (lexer) 492 | } 493 | result := & astIf 494 | debugPrint (os.Stdout, "ParseIf: => ", result, "\n") 495 | return result 496 | } 497 | 498 | // ParseCase parses: case (...) ... endcase and case (...) matches ... endcase 499 | // Current token is 'case' 500 | func ParseCase (lexer *Lexer) (AST) { 501 | debugPrint (os.Stdout, "ParseCase ...", nil, "\n") 502 | 503 | // Skip 'case' keyword 504 | GetToken (lexer) 505 | skipPunctuationMust (lexer, "(") 506 | expr := ParseExpr (lexer) 507 | skipPunctuationMust (lexer, ")") 508 | 509 | isPatternCase := TokenIsKeyword (lexer, "matches") 510 | if isPatternCase { GetToken (lexer) } 511 | 512 | var lhss [] AST 513 | var rhss [] AST 514 | 515 | for { 516 | if skipKeywordOpt (lexer, "endcase") { break } 517 | 518 | if TokenIsKeyword (lexer, "default") { 519 | lhs := makeIdeFromToken (* lexer.Token, "default") 520 | lhss = append (lhss, lhs) 521 | GetToken (lexer) 522 | } else if isPatternCase { 523 | lhss = append (lhss, ParsePattern (lexer)) 524 | } else { 525 | lhss = append (lhss, ParseExpr (lexer)) 526 | } 527 | skipPunctuationMust (lexer, ":") 528 | rhss = append (rhss, ParseStmt (lexer)) 529 | } 530 | 531 | var result AST 532 | if isPatternCase { 533 | result = & AstPatternCase {Expr: expr, Patterns: lhss, Exprs: rhss} 534 | } else { 535 | result = & AstCase {Expr: expr, Labels: lhss, Exprs: rhss} 536 | } 537 | 538 | debugPrint (os.Stdout, "ParseCase: => ", result, "\n") 539 | return result 540 | } 541 | 542 | // ParseFor parses: "for (init; cond; incr) body" 543 | // Current token is 'for' 544 | func ParseFor (lexer *Lexer) (AST) { 545 | debugPrint (os.Stdout, "ParseFor ...", nil, "\n") 546 | 547 | var astFor AstFor 548 | 549 | // Skip 'for' keyword 550 | GetToken (lexer) 551 | skipPunctuationMust (lexer, "(") 552 | astFor.LoopInit = ParseStmt (lexer) 553 | astFor.LoopCond = ParseExpr (lexer) 554 | skipPunctuationMust (lexer, ";") 555 | astFor.LoopIncr = ParseStmt (lexer) 556 | skipPunctuationMust (lexer, ")") 557 | astFor.LoopBody = ParseStmt (lexer) 558 | 559 | result := & astFor 560 | debugPrint (os.Stdout, "ParseFor: => ", result, "\n") 561 | return result 562 | } 563 | 564 | // ParseWhile parses: "while (cond) body" 565 | // Current token is 'while' 566 | func ParseWhile (lexer *Lexer) (AST) { 567 | debugPrint (os.Stdout, "ParseWhile ...", nil, "\n") 568 | 569 | var astWhile AstWhile 570 | 571 | // Skip 'while' keyword 572 | GetToken (lexer) 573 | skipPunctuationMust (lexer, "(") 574 | astWhile.LoopCond = ParseExpr (lexer) 575 | skipPunctuationMust (lexer, ")") 576 | astWhile.LoopBody = ParseStmt (lexer) 577 | 578 | result := & astWhile 579 | debugPrint (os.Stdout, "ParseWhile: => ", result, "\n") 580 | return result 581 | } 582 | 583 | // ParseInterfaceExpr parses: "interface ... endinterface" 584 | // Current token is just past 'interface' 585 | func ParseInterfaceExpr (lexer *Lexer) (* AstInterfaceExpr) { 586 | debugPrint (os.Stdout, "ParseInterfaceExpr ...", nil, "\n") 587 | 588 | var astIfc AstInterfaceExpr 589 | astIfc.Type = ParseConstIde (lexer) 590 | skipPunctuationMust (lexer, ";") 591 | 592 | astIfc.MethodAndIfcDefs = ParseStmts (lexer) 593 | 594 | skipKeywordMust (lexer, "endinterface") 595 | if skipPunctuationOpt (lexer, ":") { 596 | endide := ParseConstIde (lexer) 597 | if ! SameIde (astIfc.Type, endide) { 598 | raiseParseError (lexer, "Mismatched type names after 'interface' and 'endinterface'\n") 599 | } 600 | } 601 | 602 | result := & astIfc 603 | debugPrint (os.Stdout, "ParseInterfaceExpr: => ", result, "\n") 604 | return result 605 | } 606 | 607 | // ================================================================ 608 | -------------------------------------------------------------------------------- /parse_stmts.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Rishiyur Nikhil and Bluespec, Inc. All Rights Reserved. 2 | 3 | // Part of goParseBSV, a parser for BSV files 4 | // This part defines parsers for statements 5 | 6 | package goParseBSV 7 | 8 | import ( 9 | // golang packages 10 | "fmt" 11 | "os" 12 | "reflect" 13 | ) 14 | 15 | // ParseStmts parses a sequence of statements 16 | // Current token is the token after the opening 'begin/action/actionvalue/...' keyword 17 | func ParseStmts (lexer *Lexer) ([] AST) { 18 | debugPrint (os.Stdout, "ParseStmts ...", nil, "\n") 19 | 20 | var stmts [] AST; 21 | 22 | for { 23 | if TokenIsBlockEndKeyword (lexer) { break } 24 | stmts = append (stmts, ParseStmt (lexer)) 25 | } 26 | debugPrint (os.Stdout, "ParseStmts ==> ", nil, "\n") 27 | return stmts 28 | } 29 | 30 | // ParseStmt parses a statement 31 | // Current token is the first token of the statement 32 | func ParseStmt (lexer *Lexer) (AST) { 33 | debugPrint (os.Stdout, "ParseStmt ... ", nil, "\n") 34 | 35 | var result AST 36 | 37 | if skipPunctuationOpt (lexer, "(*") { 38 | result = ParseAttrInstance (lexer) 39 | 40 | } else if TokenIsKeyword (lexer, "let") { 41 | var astLet AstLet 42 | GetToken (lexer) 43 | astLet.Ide = ParseVarIde (lexer) 44 | if TokenIsSpecificPunctuation (lexer, "=") { 45 | GetToken (lexer) 46 | astLet.Kind = BindingKindEq 47 | } else { 48 | skipPunctuationMust (lexer, "<-") 49 | astLet.Kind = BindingKindLArrow 50 | } 51 | astLet.Expr = ParseExpr (lexer) 52 | result = & astLet 53 | 54 | } else if TokenIsKeyword (lexer, "match") { 55 | var astMatch AstMatch 56 | GetToken (lexer) 57 | astMatch.Pattern = ParsePattern (lexer) 58 | skipPunctuationMust (lexer, "=") 59 | astMatch.Expr = ParseExpr (lexer) 60 | result = & astMatch 61 | 62 | } else if TokenIsKeyword (lexer, "function") { 63 | result = ParseFunctionDef (lexer) 64 | 65 | } else if TokenIsKeyword (lexer, "method") { 66 | result = ParseMethodDef (lexer) 67 | 68 | } else if TokenIsKeyword (lexer, "interface") { 69 | result = ParseInterfaceDef (lexer) 70 | 71 | } else if TokenIsKeyword (lexer, "module") { 72 | result = ParseModuleDef (lexer) 73 | 74 | } else if TokenIsKeyword (lexer, "rule") { 75 | result = ParseRule (lexer) 76 | 77 | } else if TokenIsKeyword (lexer, "if") { 78 | result = ParseIf (lexer) 79 | 80 | } else if TokenIsKeyword (lexer, "for") { 81 | result = ParseFor (lexer) 82 | 83 | } else if TokenIsKeyword (lexer, "while") { 84 | result = ParseWhile (lexer) 85 | 86 | } else { 87 | result = ParseVarDeclOrAssign (lexer) 88 | } 89 | skipPunctuationOpt (lexer, ";") 90 | 91 | debugPrint (os.Stdout, "ParseStmt: => ", result, "\n") 92 | return result 93 | } 94 | 95 | // Strategy for ParseVarDeclOrAssign: 96 | 97 | // Statements include 'e', 'type lhs=rhs' and 'lhs=rhs'. So, we don't 98 | // know initially whether we're parsing an expression, a type, or 99 | // an lhs. Thus, we first parse an expression. If the next token 100 | // is an identifier, the expression we just parsed is actually a 101 | // type and the next token starts an lhs. 102 | 103 | // ParseVarDeclOrAssign parses 104 | // variable declarations with '=' initializers: type varOrArray = e, varOrArray=e, ..., 105 | // variable declarations with '<-' assignment: type var <- e 106 | // variable = assignments: lhs = e 107 | // variable '<-' assignments: x <- e 108 | func ParseVarDeclOrAssign (lexer *Lexer) (AST) { 109 | debugPrint (os.Stdout, "ParseVarDeclOrAssign ... ", nil, "\n") 110 | 111 | var result AST 112 | 113 | ast := ParseExpr (lexer) // may be a type, actually 114 | 115 | if skipPunctuationOpt (lexer, "=") { 116 | // '=' assignment of a previously declared variable 117 | // TODO: check that ast is a legal lvalue 118 | var astAssign AstAssign 119 | astAssign.Lhs = ast 120 | astAssign.Kind = BindingKindEq 121 | astAssign.Rhs = ParseExpr (lexer) 122 | result = & astAssign 123 | 124 | } else if skipPunctuationOpt (lexer, "<-") { 125 | // '<-' assignment of a previously declared variable 126 | // TODO: check that ast is a varIde 127 | var astAssign AstAssign 128 | astAssign.Lhs = ast 129 | astAssign.Kind = BindingKindLArrow 130 | astAssign.Rhs = ParseExpr (lexer) 131 | result = & astAssign 132 | 133 | } else if (! canBeTypeExpr (ast)) { 134 | result = ast 135 | 136 | } else if TokenIsIde (lexer) { 137 | astType := convertExprToTypeExpr (lexer, ast) 138 | result = ParseVarDecl (lexer, astType) 139 | 140 | } else { 141 | result = ast 142 | } 143 | 144 | debugPrint (os.Stdout, "ParseVarDeclOrAssign: => ", result, "\n") 145 | return result 146 | } 147 | 148 | // ParseVarDecl parses variable-declaration statement: type varInit, varInit, ... ; 149 | // variable declarations with '=' initializers: type varOrArray = e, varOrArray=e, ..., 150 | // variable declarations with '<-' assignment: type var <- e 151 | // Current token is first lhs 152 | func ParseVarDecl (lexer *Lexer, astType AST) (AST) { 153 | debugPrint (os.Stdout, "ParseVarDecl ... ", nil, "\n") 154 | 155 | var ast AstVarDecl 156 | 157 | ast.Type = astType 158 | debugPrint (os.Stdout, "ParseVarDecl Type: ", ast.Type, "\n") 159 | 160 | // Get varInit, ..., varInit ; 161 | for { 162 | if TokenIsSpecificPunctuation (lexer, ";") { break } 163 | varInit := ParseVarInit (lexer) 164 | ast.VarInits = append (ast.VarInits, varInit) 165 | if ! TokenIsSpecificPunctuation (lexer, ";") { 166 | skipPunctuationMust (lexer, ",") 167 | } 168 | } 169 | 170 | debugPrint (os.Stdout, "ParseVarDecl: => ", & ast, "\n") 171 | return & ast 172 | } 173 | 174 | // ParseVarInit parses an assignment 'Ide [e]...[e] = Expr;' 175 | func ParseVarInit (lexer *Lexer) (*AstVarInit) { 176 | debugPrint (os.Stdout, "ParseVarInit ... ", nil, "\n") 177 | 178 | var astVarInit AstVarInit 179 | 180 | // Get identifier being defined 181 | astVarInit.Ide = ParseVarIde (lexer) 182 | debugPrint (os.Stdout, "ParseVarInit Ide: ", astVarInit.Ide, "\n") 183 | 184 | // Get array dims, if any 185 | for skipPunctuationOpt (lexer, "[") { 186 | arrayDim := ParseExpr (lexer) 187 | skipPunctuationMust (lexer, "]") 188 | astVarInit.ArrayDims = append (astVarInit.ArrayDims, arrayDim) 189 | debugPrint (os.Stdout, "ParseVarInit arrayDim: ", arrayDim, "\n") 190 | } 191 | 192 | // Get initializer, if any 193 | if skipPunctuationOpt (lexer, "=") { 194 | astVarInit.Kind = BindingKindEq 195 | astVarInit.Init = ParseExpr (lexer) 196 | debugPrint (os.Stdout, "ParseVarInit = Init:", astVarInit.Init, "\n") 197 | 198 | } else if skipPunctuationOpt (lexer, "<-") { 199 | astVarInit.Kind = BindingKindLArrow 200 | astVarInit.Init = ParseExpr (lexer) 201 | debugPrint (os.Stdout, "ParseVarInit <- Init:", astVarInit.Init, "\n") 202 | } else { 203 | astVarInit.Kind = BindingKindNone 204 | } 205 | 206 | debugPrint (os.Stdout, "ParseVarInit: => ", & astVarInit, "\n") 207 | return & astVarInit 208 | } 209 | 210 | // ParseRule parses 'rule ... endrule' 211 | // Current token is 'rule' keyword 212 | func ParseRule (lexer *Lexer) (AST) { 213 | debugPrint (os.Stdout, "ParseRule ... ", nil, "\n") 214 | 215 | var astRule AstRule 216 | 217 | // Skip past 'rule' keyword 218 | GetToken (lexer) 219 | 220 | // Get the rule name 221 | astRule.Name = ParseIde (lexer) 222 | 223 | if skipPunctuationOpt (lexer, "(") { 224 | astRule.Cond = ParseExpr (lexer) 225 | skipPunctuationMust (lexer, ")") 226 | } 227 | skipPunctuationMust (lexer, ";") 228 | 229 | // Get rule body 230 | astRule.Stmts = ParseStmts (lexer) 231 | 232 | // Parse the 'endrule' keyword 233 | skipKeywordMust (lexer, "endrule") 234 | 235 | // TODO: optional repeat of rulename after endrule 236 | 237 | result := & astRule 238 | debugPrint (os.Stdout, "ParseRule: => ", result, "\n") 239 | return result 240 | } 241 | 242 | // ParseFunctionProto parses 'function type name (type formal, ..., type formal)' 243 | // Current token is 'function' keyword 244 | func parseFunctionProto (lexer *Lexer) (*AstFunctionProto) { 245 | debugPrint (os.Stdout, "ParseFunctionProto ... ", nil, "\n") 246 | 247 | var astFunctionProto AstFunctionProto 248 | 249 | // Skip past 'function' keyword 250 | GetToken (lexer) 251 | 252 | astFunctionProto.ResultType = ParseTypeExpr (lexer) 253 | debugPrint (os.Stdout, "ParseFunctionProto ResultType: ", astFunctionProto.ResultType, "\n") 254 | 255 | astFunctionProto.Name = ParseVarIde (lexer) 256 | debugPrint (os.Stdout, "ParseFunctionProto Name ", astFunctionProto.Name, "\n") 257 | 258 | if skipPunctuationOpt (lexer, "(") { 259 | for { 260 | if skipPunctuationOpt (lexer, ")") { break } 261 | astFunctionProto.FormalTypes = append (astFunctionProto.FormalTypes, ParseTypeExpr (lexer)) 262 | astFunctionProto.Formals = append (astFunctionProto.Formals, ParseVarIde (lexer)) 263 | if ! TokenIsSpecificPunctuation (lexer, ")") { 264 | skipPunctuationMust (lexer, ",") 265 | } 266 | } 267 | } 268 | 269 | return & astFunctionProto 270 | } 271 | 272 | // ParseFunctionDef parses 'function ... endfunction' or 'function ... = e' 273 | // Current token is 'function' keyword 274 | func ParseFunctionDef (lexer *Lexer) (AST) { 275 | debugPrint (os.Stdout, "ParseFunctionDef ... ", nil, "\n") 276 | 277 | var astFuncDef AstFunctionDef 278 | 279 | // Parse the function prototype 280 | astFuncDef.Proto = parseFunctionProto (lexer) 281 | 282 | // Get optional provisos 283 | if TokenIsKeyword (lexer, "provisos") { 284 | astFuncDef.Provisos = ParseProvisos (lexer) 285 | } 286 | 287 | if TokenIsSpecificPunctuation (lexer, "=") { 288 | // Body is assigned 289 | GetToken (lexer) 290 | astFuncDef.Body = ParseExpr (lexer) 291 | 292 | } else { 293 | // Body is a block 294 | skipPunctuationMust (lexer, ";") 295 | var stmts [] AST = ParseStmts (lexer) 296 | // Parse the 'endfunction' keyword 297 | if ! TokenIsKeyword (lexer, "endfunction") { 298 | raiseParseError (lexer, "Expecting 'endfunction'\n") 299 | } 300 | GetToken (lexer) 301 | astFuncDef.Body = & AstBlock {BlockKind: "begin", BlockName: nil, Stmts: stmts} 302 | } 303 | 304 | debugPrint (os.Stdout, "ParseFunctionDef: => ", & astFuncDef, "\n") 305 | return & astFuncDef 306 | } 307 | 308 | // ParseMethodDef parses 'method ... endmethod' or 'method ... = e' 309 | // Current token is 'method' keyword 310 | func ParseMethodDef (lexer *Lexer) (AST) { 311 | debugPrint (os.Stdout, "ParseMethodDef ... ", nil, "\n") 312 | 313 | var astMethodDef AstMethodDef 314 | 315 | // Skip past 'method' keyword 316 | GetToken (lexer) 317 | 318 | astMethodDef.ResultType = ParseTypeExpr (lexer) 319 | debugPrint (os.Stdout, "ParseMethodDef ResultType: ", astMethodDef.ResultType, "\n") 320 | 321 | astMethodDef.Name = ParseVarIde (lexer) 322 | debugPrint (os.Stdout, "ParseMethodDef Name ", astMethodDef.Name, "\n") 323 | 324 | // Get optional formal params 325 | if skipPunctuationOpt (lexer, "(") { 326 | for { 327 | if skipPunctuationOpt (lexer, ")") { break } 328 | astMethodDef.FormalTypes = append (astMethodDef.FormalTypes, ParseTypeExpr (lexer)) 329 | astMethodDef.Formals = append (astMethodDef.Formals, ParseVarIde (lexer)) 330 | if ! TokenIsSpecificPunctuation (lexer, ")") { 331 | skipPunctuationMust (lexer, ",") 332 | } 333 | } 334 | } 335 | 336 | // Get optional method condition 337 | if skipKeywordOpt (lexer, "if") { 338 | astMethodDef.Cond = ParseExpr (lexer) 339 | } 340 | 341 | if skipPunctuationOpt (lexer, "=") { 342 | astMethodDef.Body = ParseExpr (lexer) 343 | } else { 344 | skipPunctuationMust (lexer, ";") 345 | var stmts [] AST = ParseStmts (lexer) 346 | // Parse the 'endmethod' keyword 347 | if ! TokenIsKeyword (lexer, "endmethod") { 348 | raiseParseError (lexer, "Expecting 'endmethod'\n") 349 | } 350 | GetToken (lexer) 351 | astMethodDef.Body = & AstBlock {BlockKind: "begin", BlockName: nil, Stmts: stmts} 352 | } 353 | 354 | debugPrint (os.Stdout, "ParseMethodDef: => ", & astMethodDef, "\n") 355 | return & astMethodDef 356 | } 357 | 358 | // ParseInterfaceDef parses 'interface ... endinterface' or 'interface ... = e' 359 | // Current token is 'interface' keyword 360 | func ParseInterfaceDef (lexer *Lexer) (AST) { 361 | debugPrint (os.Stdout, "ParseInterfaceDef ... ", nil, "\n") 362 | 363 | var result AST 364 | 365 | // Skip past 'interface' keyword 366 | GetToken (lexer) 367 | 368 | var typ AST = nil 369 | var name *AstIde = nil 370 | // Get the optional type of the interface being defined 371 | e := ParseExpr (lexer) 372 | 373 | if TokenIsIde (lexer) { 374 | // e was the type; convert it into a type expr 375 | typ = convertExprToTypeExpr (lexer, e) 376 | // Get the interface name 377 | name = ParseVarIde (lexer) 378 | } else { 379 | // e was the identifier 380 | ide, ok := e.(*AstIde) 381 | if ! ok { 382 | raiseParseError (lexer, "Expecting interface name\n") 383 | } 384 | name = ide 385 | } 386 | 387 | if skipPunctuationOpt (lexer, "=") { 388 | // Interface assign 389 | var aia AstInterfaceAssign 390 | aia.Type = typ 391 | aia.Name = name 392 | aia.Val = ParseExpr (lexer) 393 | result = & aia 394 | 395 | } else { 396 | // Interface def 397 | skipPunctuationMust (lexer, ";") 398 | 399 | var aid AstInterfaceDef 400 | aid.Type = typ 401 | aid.Name = name 402 | aid.MethodAndIfcDefs = ParseStmts (lexer) 403 | skipKeywordMust (lexer, "endinterface") 404 | result = & aid 405 | } 406 | 407 | debugPrint (os.Stdout, "ParseInterfaceDef: => ", result, "\n") 408 | return result 409 | } 410 | 411 | // ParseModuleDef parses 'module ... endmodule' 412 | // Current token is 'module' keyword 413 | func ParseModuleDef (lexer *Lexer) (*AstModuleDef) { 414 | debugPrint (os.Stdout, "ParseModuleDef ... ", nil, "\n") 415 | 416 | var astModDef AstModuleDef 417 | 418 | // Skip past 'module' keyword 419 | GetToken (lexer) 420 | 421 | // Get the optional module type 422 | if skipPunctuationOpt (lexer, "[") { 423 | astModDef.ModuleType = ParseTypeExpr (lexer) 424 | debugPrint (os.Stdout, "ParseModuleDef ModuleType: ", astModDef.ModuleType, "\n") 425 | skipPunctuationMust (lexer, "]") 426 | } 427 | 428 | // Get the module name 429 | astModDef.Name = ParseVarIde (lexer) 430 | debugPrint (os.Stdout, "ParseModuleDef Name ", astModDef.Name, "\n") 431 | 432 | // Get optional params 433 | if skipPunctuationOpt (lexer, "#") { 434 | skipPunctuationMust (lexer, "(") 435 | for { 436 | if skipPunctuationOpt (lexer, ")") { break } 437 | astModDef.FormalParamTypes = append (astModDef.FormalParamTypes, ParseTypeExpr (lexer)) 438 | astModDef.FormalParams = append (astModDef.FormalParams, ParseVarIde (lexer)) 439 | if ! TokenIsSpecificPunctuation (lexer, ")") { 440 | skipPunctuationMust (lexer, ",") 441 | } 442 | } 443 | } 444 | 445 | // Get the interface type 446 | skipPunctuationMust (lexer, "(") 447 | astModDef.IfcType = ParseTypeExpr (lexer) 448 | skipPunctuationMust (lexer, ")") 449 | 450 | // Get optional provisos 451 | if TokenIsKeyword (lexer, "provisos") { 452 | astModDef.Provisos = ParseProvisos (lexer) 453 | } 454 | 455 | skipPunctuationMust (lexer, ";") 456 | 457 | // Get the module statements 458 | astModDef.Stmts = ParseStmts (lexer) 459 | 460 | // Parse the 'endmodule' keyword 461 | skipKeywordMust (lexer, "endmodule") 462 | 463 | if skipPunctuationOpt (lexer, ":") { 464 | endide := ParseVarIde (lexer) 465 | if ! SameIde (astModDef.Name, endide) { 466 | raiseParseError (lexer, "Mismatched module names after 'module' and 'endmodule'\n") 467 | } 468 | 469 | } 470 | 471 | result := & astModDef 472 | debugPrint (os.Stdout, "ParseModuleDef: => ", result, "\n") 473 | return result 474 | } 475 | 476 | // Parse 'provisos (...)' 477 | // Current token is 'provisos' 478 | func ParseProvisos (lexer *Lexer) ([] AST) { 479 | var result [] AST 480 | GetToken (lexer) 481 | skipPunctuationMust (lexer, "(") 482 | for { 483 | if TokenIsSpecificPunctuation (lexer, ")") { break } 484 | result = append (result, ParseTypeExpr (lexer)) 485 | if ! TokenIsSpecificPunctuation (lexer, ")") { 486 | skipPunctuationMust (lexer, ",") 487 | } 488 | } 489 | GetToken (lexer) 490 | return result 491 | } 492 | 493 | // ================================================================ 494 | // Conversion of an Expr into a TypeExpr 495 | 496 | // Predicate to check whether an expr can be a type expr 497 | 498 | func canBeTypeExpr (ast AST) (bool) { 499 | debugPrint (os.Stdout, "canBeTypeExpr: ", ast, "\n") 500 | 501 | var result bool 502 | 503 | switch x := ast.(type) { 504 | 505 | case *AstNum: 506 | result = true 507 | 508 | case *AstIde: 509 | result = true 510 | 511 | case *AstExpr: 512 | // Check that this is an application with at least one component 513 | if (! AST_isSpecificIde (x.Expr0, "Apply")) { 514 | // Not an application 515 | result = false 516 | 517 | } else if len (x.Exprs) < 1 { 518 | // x.Exprs does not contain even 1 element (the type constructor) 519 | result = false 520 | 521 | } else if ! AST_isConstIde (x.Exprs [0]) { 522 | // x.Exprs [0] is not a Type Constructor 523 | result = false 524 | 525 | } else { 526 | // Check that the remaining components can be type exprs 527 | result = true 528 | for _, ast_e := range (x.Exprs [1:]) { 529 | result = result && canBeTypeExpr (ast_e) 530 | } 531 | } 532 | 533 | default: 534 | result = false 535 | } 536 | 537 | if debug { 538 | fmt.Fprintf (os.Stdout, "canBeTypeExpr: => %v\n", result) 539 | } 540 | return result 541 | } 542 | 543 | // Converts the arg, which is an Expr AST into a TypeExpr AST 544 | func convertExprToTypeExpr (lexer *Lexer, ast AST) (AST) { 545 | debugPrint (os.Stdout, "convertExprToTypeExpr: ", ast, "\n") 546 | 547 | var result AST 548 | switch x := ast.(type) { 549 | 550 | case *AstNum: 551 | result = & AstTypeNum { LeafValue: x.LeafValue } 552 | 553 | case *AstIde: 554 | result = & AstTypeVar { LeafValue: x.LeafValue } 555 | 556 | case *AstExpr: 557 | err := false 558 | 559 | // Check that this is an application with at least one component 560 | if (! AST_isSpecificIde (x.Expr0, "Apply")) { 561 | err = true 562 | 563 | } else if len (x.Exprs) < 1 { 564 | // x.Exprs does not contain even 1 element (the type constructor) 565 | err = true 566 | } 567 | 568 | if err { 569 | fmt.Fprintf (os.Stderr, "ERROR: ConverExprToTypeExpr: illegal type expression\n") 570 | AST_pp (os.Stderr, "", ast) 571 | fmt.Fprintf (os.Stderr, "\n") 572 | fmt.Fprintf (os.Stderr, " Expecting a type constructor applied to type args\n") 573 | raiseParseError (lexer, "Not a valid type expression\n") 574 | 575 | } else { 576 | // Check that the type constructor is an Identifier 577 | if ! AST_isConstIde (x.Exprs [0]) { 578 | fmt.Fprintf (os.Stderr, "ERROR: ConverExprToTypeExpr: illegal type expression\n") 579 | AST_pp (os.Stderr, "", ast) 580 | fmt.Fprintf (os.Stderr, "\n") 581 | fmt.Fprintf (os.Stderr, " Expecting a type constructor\n") 582 | raiseParseError (lexer, "Not a valid type expression\n") 583 | 584 | } else { 585 | tycon, _ := (x.Exprs [0]).(*AstIde) 586 | 587 | ast_ts := make ([] AST, 0, len (x.Exprs) - 1) 588 | for _, ast_e := range (x.Exprs [1:]) { 589 | ast_ts = append (ast_ts, convertExprToTypeExpr (lexer, ast_e)) 590 | } 591 | result = & AstTypeConstructed {Constructor: tycon, Args: ast_ts} 592 | } 593 | } 594 | 595 | default: 596 | fmt.Fprintf (os.Stderr, "ERROR: ConverExprToTypeExpr: illegal type expression\n") 597 | AST_pp (os.Stderr, "", ast) 598 | fmt.Fprintf (os.Stderr, " ast type is: %v\n", reflect.TypeOf (ast)) 599 | raiseParseError (lexer, "Not a type expression\n") 600 | } 601 | 602 | debugPrint (os.Stdout, "convertExprToTypeExpr: => ", result, "\n") 603 | return result 604 | } 605 | 606 | // ================================================================ 607 | -------------------------------------------------------------------------------- /parser.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Rishiyur Nikhil and Bluespec, Inc. All Rights Reserved. 2 | 3 | // goParseBSV is a parser for BSV files. 4 | // This is the top-level file of the parser. 5 | 6 | package goParseBSV 7 | 8 | import ( 9 | // golang packages 10 | "fmt" 11 | "os" 12 | "strings" 13 | ) 14 | 15 | // ================================================================ 16 | // For debugging the parser itself. 17 | 18 | var debug bool = false 19 | 20 | func debugPrint (fout *os.File, pre string, ast AST, post string) () { 21 | if debug { 22 | fmt.Fprintf (fout, "%s", pre) 23 | if (ast != nil) { AST_pp (fout, "", ast) } 24 | fmt.Fprintf (fout, "%s", post) 25 | } 26 | } 27 | 28 | // ---------------------------------------------------------------- 29 | 30 | func raiseParseError (lexer *Lexer, msg string) { 31 | fmt.Fprintf (os.Stderr, "ERROR: %s", msg) 32 | lexer.PrintToken (os.Stderr, " ") 33 | os.Exit (1) 34 | } 35 | 36 | // ================================================================ 37 | // Useful predicates on tokens and identifier ASTs 38 | 39 | func TokenIsSpecificPunctuation (lexer *Lexer, s string) (bool) { 40 | token := lexer.Token 41 | if token.TokType != TokOther { return false } 42 | if token.StringVal != s { return false } 43 | return true 44 | } 45 | 46 | func TokenIsSpecificString (lexer *Lexer, s string) (bool) { 47 | token := lexer.Token 48 | if token.TokType != TokString { return false } 49 | if token.StringVal != s { return false } 50 | return true 51 | } 52 | 53 | func TokenIsIde (lexer *Lexer) (bool) { 54 | token := lexer.Token 55 | if token.TokType != TokIde { return false } 56 | return true 57 | } 58 | 59 | // tokenIsVarIde checks for BSV variable identifiers, i.e., first letter is lowercase 60 | func tokenIsVarIde (token *Token) (bool) { 61 | return ((token != nil) && 62 | (token.TokType == TokIde) && 63 | (ByteIsLower (token.StringVal [0]) || (token.StringVal [0] == '_'))) 64 | } 65 | 66 | // tokenIsConstIde checks for BSV constant identifiers, i.e., first letter is uppercase 67 | func tokenIsConstIde (token *Token) (bool) { 68 | return ((token != nil) && 69 | (token.TokType == TokIde) && 70 | (ByteIsUpper (token.StringVal [0]))) 71 | } 72 | 73 | func TokenIsKeyword (lexer *Lexer, s string) (bool) { 74 | token := lexer.Token 75 | if token.TokType != TokKeyword { return false } 76 | if token.StringVal != s { return false } 77 | return true 78 | } 79 | 80 | func TokenIsBlockEndKeyword (lexer *Lexer) (bool) { 81 | tok := lexer.Token 82 | s := tok.StringVal 83 | b1 := (tok.TokType == TokKeyword) 84 | b2 := ( (s == "end") || 85 | (s == "endfunction") || 86 | (s == "endrule") || 87 | (s == "endmethod") || 88 | (s == "endinterface") || 89 | (s == "endmodule") || 90 | (s == "endaction") || 91 | (s == "endactionvalue")) 92 | return b1 && b2 93 | } 94 | 95 | func SameIde (ide1 *AstIde, ide2 *AstIde) (bool) { 96 | tok1 := ide1.LeafValue 97 | tok2 := ide2.LeafValue 98 | return (tok1.TokType == TokIde) && 99 | (tok2.TokType == TokIde) && 100 | (tok1.StringVal == tok2.StringVal) 101 | } 102 | 103 | func AST_isVarIde (ast AST) (bool) { 104 | astIde, ok := ast.(*AstIde) 105 | return ok && tokenIsVarIde (astIde.LeafValue) 106 | } 107 | 108 | func AST_isConstIde (ast AST) (bool) { 109 | astIde, ok := ast.(*AstIde) 110 | return ok && tokenIsConstIde (astIde.LeafValue) 111 | } 112 | 113 | func AST_isSpecificIde (ast AST, s string) (bool) { 114 | astIde, ok := ast.(*AstIde) 115 | return (ok && 116 | (astIde.LeafValue != nil) && 117 | (astIde.LeafValue.TokType == TokIde) && 118 | (astIde.LeafValue.StringVal == s)) 119 | } 120 | 121 | // ================================================================ 122 | // Consuming punctuation and keywords 123 | // Tokens like { } < > [ ] ( ) ; : # , . 124 | 125 | // skipPunctuationOpt skips an optional bit of punctuation "s" 126 | // If found, consume, and return true 127 | // else don't consume, and return false 128 | func skipPunctuationOpt (lexer *Lexer, s string) (bool) { 129 | tok := lexer.Token 130 | if (tok.TokType == TokOther) && (tok.StringVal == s) { 131 | GetToken (lexer) 132 | return true 133 | } else { 134 | return false 135 | } 136 | } 137 | 138 | // skipPunctuationMust skips a necessary bit of punctuation "s" 139 | func skipPunctuationMust (lexer *Lexer, s string) () { 140 | tok := lexer.Token 141 | if (tok.TokType == TokOther) && (tok.StringVal == s) { 142 | GetToken (lexer) 143 | } else { 144 | raiseParseError (lexer, fmt.Sprintf ("expecting %q\n", s)) 145 | } 146 | } 147 | 148 | // skipKeywordOpt skips a necessary identifier. 149 | // If found, consume, and return true 150 | // else don't consume, and return false 151 | func skipKeywordOpt (lexer *Lexer, s string) (bool) { 152 | tok := lexer.Token 153 | if (tok.TokType == TokKeyword) && (tok.StringVal == s) { 154 | GetToken (lexer) 155 | return true 156 | } else { 157 | return false 158 | } 159 | } 160 | 161 | // skipKeywordMust skips a necessary keyword 162 | func skipKeywordMust (lexer *Lexer, s string) () { 163 | tok := lexer.Token 164 | if (tok.TokType == TokKeyword) && (tok.StringVal == s) { 165 | GetToken (lexer) 166 | } else { 167 | raiseParseError (lexer, fmt.Sprintf ("expecting keyword %q\n", s)) 168 | } 169 | } 170 | 171 | // ================================================================ 172 | // Ides 173 | 174 | func assertIsIde (lexer *Lexer) () { 175 | if (lexer.Token.TokType != TokIde) { 176 | raiseParseError (lexer, "Expecting an identifier\n") 177 | } 178 | } 179 | 180 | // Make an identifier with the given string from the given token 181 | func makeIdeFromToken (tok Token, s string) (*AstIde) { 182 | tok.TokType = TokIde 183 | tok.StringVal = s 184 | ast := AstIde {LeafValue: & tok} 185 | return & ast 186 | } 187 | 188 | // ParseIde parses and returns an identifier 189 | func ParseIde (lexer *Lexer) (*AstIde) { 190 | assertIsIde (lexer) 191 | ast := AstIde {LeafValue: lexer.Token} 192 | GetToken (lexer) 193 | return & ast 194 | } 195 | 196 | // ParseVarIde parses and returns an identifier that is a varIde (lowercase first letter) 197 | func ParseVarIde (lexer *Lexer) (*AstIde) { 198 | if tokenIsVarIde (lexer.Token) { 199 | ast := AstIde {LeafValue: lexer.Token} 200 | GetToken (lexer) 201 | return & ast 202 | } else { 203 | raiseParseError (lexer, "Expecting a var identifier (first letter lowercase)\n") 204 | return nil 205 | } 206 | } 207 | 208 | // ParseConstIde parses and returns an identifier that is a varIde (lowercase first letter) 209 | func ParseConstIde (lexer *Lexer) (*AstIde) { 210 | if tokenIsConstIde (lexer.Token) { 211 | ast := AstIde {LeafValue: lexer.Token} 212 | GetToken (lexer) 213 | return & ast 214 | } else { 215 | raiseParseError (lexer, "Expecting a const identifier (first letter uppercase)\n") 216 | return nil 217 | } 218 | } 219 | 220 | // ================================================================ 221 | // Parse all top-level decls in a package 222 | 223 | // ParsePackage is the top-level function to parse a BSV source file. 224 | func ParsePackage (lexer *Lexer) (AST) { 225 | 226 | var ast AstPackage 227 | 228 | if skipKeywordOpt (lexer, "package") { 229 | ast.PackageName = ParseIde (lexer) 230 | skipPunctuationMust (lexer, ";") 231 | } 232 | 233 | for { 234 | if (lexer.Token.TokType == TokEof) && (ast.PackageName == nil) { 235 | break 236 | 237 | } else if skipPunctuationOpt (lexer, ";") { 238 | 239 | } else if skipPunctuationOpt (lexer, "(*") { 240 | attri := ParseAttrInstance (lexer) 241 | ast.PackageStmts = append (ast.PackageStmts, attri) 242 | continue 243 | 244 | } else if skipKeywordOpt (lexer, "import") { 245 | importStmt := ParseImport (lexer) 246 | ast.PackageStmts = append (ast.PackageStmts, importStmt) 247 | continue 248 | 249 | } else if skipKeywordOpt (lexer, "export") { 250 | exportStmt := ParseExport (lexer) 251 | ast.PackageStmts = append (ast.PackageStmts, exportStmt) 252 | continue 253 | 254 | } else if skipKeywordOpt (lexer, "interface") { 255 | decl := ParseInterfaceDecl (lexer) 256 | ast.PackageStmts = append (ast.PackageStmts, decl) 257 | continue 258 | 259 | } else if skipKeywordOpt (lexer, "typedef") { 260 | decl := ParseTypedef (lexer) 261 | ast.PackageStmts = append (ast.PackageStmts, decl) 262 | continue 263 | 264 | } else if TokenIsKeyword (lexer, "function") { 265 | decl := ParseFunctionDef (lexer) 266 | ast.PackageStmts = append (ast.PackageStmts, decl) 267 | continue 268 | 269 | } else if TokenIsKeyword (lexer, "instance") { 270 | decl := ParseInstance (lexer) 271 | ast.PackageStmts = append (ast.PackageStmts, decl) 272 | continue 273 | 274 | } else if TokenIsKeyword (lexer, "module") { 275 | decl := ParseModuleDef (lexer) 276 | ast.PackageStmts = append (ast.PackageStmts, decl) 277 | continue 278 | 279 | } else if skipKeywordOpt (lexer, "endpackage") { 280 | isColon := skipPunctuationOpt (lexer, ":") 281 | if isColon { 282 | endPkgName := ParseIde (lexer) 283 | if ! SameIde (ast.PackageName, endPkgName) { 284 | fmt.Fprintf (os.Stderr, "WARNING: 'package ") 285 | AST_pp (os.Stderr, "", ast.PackageName) 286 | fmt.Fprintf (os.Stderr, "' does not match 'endpackage:") 287 | AST_pp (os.Stderr, "", endPkgName) 288 | fmt.Fprintf (os.Stderr, "' (ignoring this)\n") 289 | printLocation (os.Stdout, lexer, " ") 290 | } 291 | } 292 | break 293 | } else { 294 | decl := ParseVarDeclOrAssign (lexer) 295 | ast.PackageStmts = append (ast.PackageStmts, decl) 296 | continue 297 | } 298 | /* 299 | } else { 300 | fmt.Fprintf (os.Stdout, "Stopping at:\n") 301 | printLocation (os.Stdout, lexer, " ") 302 | raiseParseError (lexer, "Unrecognized input token") 303 | break 304 | } 305 | */ 306 | } 307 | return & ast 308 | } 309 | 310 | // ================================================================ 311 | // Parse an import statement 312 | 313 | // ParseImport parses an import line 314 | // E.g., "import packagename :: *;" 315 | func ParseImport (lexer *Lexer) (AST) { 316 | 317 | // "import" keyword already consumed 318 | 319 | if ! TokenIsSpecificString (lexer, "BDPI") { 320 | var astImport AstImport 321 | 322 | astImport.PackageName = ParseIde (lexer) 323 | skipPunctuationMust (lexer, "::") 324 | skipPunctuationMust (lexer, "*") 325 | skipPunctuationMust (lexer, ";") 326 | return & astImport 327 | 328 | } else { 329 | GetToken (lexer) 330 | var astImportBDPI AstImportBDPI 331 | astImportBDPI.Proto = parseFunctionProto (lexer) 332 | return & astImportBDPI 333 | } 334 | } 335 | 336 | // ================================================================ 337 | // Parse an export statement 338 | 339 | // ParseExport parses an export line 340 | // E.g., "export x, y(..), Z;" 341 | // Current token is just after "export" keyword 342 | func ParseExport (lexer *Lexer) (AST) { 343 | 344 | var astExport AstExport 345 | 346 | for { 347 | if skipPunctuationOpt (lexer, ";") { break } 348 | ide := ParseIde (lexer) 349 | withMembers := false 350 | if skipPunctuationOpt (lexer, "(") { 351 | skipPunctuationMust (lexer, "..") 352 | skipPunctuationMust (lexer, ")") 353 | withMembers = true 354 | } 355 | astExport.Ides = append (astExport.Ides, ide) 356 | astExport.WithMembers = append (astExport.WithMembers, withMembers) 357 | if ! TokenIsSpecificPunctuation (lexer, ";") { 358 | skipPunctuationMust (lexer, ",") 359 | } 360 | } 361 | result := & astExport 362 | debugPrint (os.Stdout, "ParseExport: => ", result, "\n") 363 | return result 364 | } 365 | 366 | // ================================================================ 367 | // Parse an attribute instance 368 | 369 | // ParseAttrInstance parses (* ide, ide=expr, ide, ... *) 370 | // Current token is just after (* opening token 371 | func ParseAttrInstance (lexer *Lexer) (AST) { 372 | 373 | var attr AstAttrInstance 374 | 375 | for { 376 | if skipPunctuationOpt (lexer, "*)") { break } 377 | ide := ParseIde (lexer) 378 | var val AST = nil 379 | if skipPunctuationOpt (lexer, "=") { 380 | val = ParseExpr (lexer) 381 | } 382 | attr.Ides = append (attr.Ides, ide) 383 | attr.Vals = append (attr.Vals, val) 384 | if ! TokenIsSpecificPunctuation (lexer, "*)") { 385 | skipPunctuationMust (lexer, ",") 386 | } 387 | } 388 | result := & attr 389 | debugPrint (os.Stdout, "ParseAttrInstance: => ", result, "\n") 390 | return result 391 | } 392 | 393 | // ================================================================ 394 | // typedef statements 395 | // e.g., "typedef typeDefinedAs newtype deriving (typeclass, ...);" 396 | 397 | // ParseTypedef parses a BSV statement: 'typedef typeDefinedAs newtype deriving (typeclass, ...);' 398 | func ParseTypedef (lexer *Lexer) (result *AstTypedef) { 399 | // "typedef" keyword already consumed. 400 | var ast AstTypedef 401 | 402 | // Parse the definedAs (enum, struct, union tagged, or existing type) 403 | if skipKeywordOpt (lexer, "enum") { 404 | ast.TypedefDefinedAs = ParseTypedefDefinedAsEnum (lexer) 405 | } else if skipKeywordOpt (lexer, "struct") { 406 | ast.TypedefDefinedAs = ParseTypedefDefinedAsStruct (lexer) 407 | } else if skipKeywordOpt (lexer, "union") { 408 | skipKeywordMust (lexer, "tagged") 409 | ast.TypedefDefinedAs = ParseTypedefDefinedAsTaggedUnion (lexer) 410 | } else { 411 | ast.TypedefDefinedAs = ParseTypeExpr (lexer) 412 | } 413 | 414 | // Parse the definee (the type being defined) 415 | ast.TypedefDefinee = ParseTypedefDefinee (lexer) 416 | 417 | // Parse "deriving(..)" clause 418 | derivingFound := skipKeywordOpt (lexer, "deriving") 419 | if derivingFound { 420 | skipPunctuationMust (lexer, "("); 421 | for { 422 | rparenFound := skipPunctuationOpt (lexer, ")"); 423 | if rparenFound { break } 424 | deriveType := ParseIde (lexer); 425 | ast.TypeclassIdes = append (ast.TypeclassIdes, deriveType) 426 | if ! TokenIsSpecificPunctuation (lexer, ")") { 427 | skipPunctuationMust (lexer, ",") 428 | } 429 | } 430 | } 431 | skipPunctuationMust (lexer, ";") 432 | result = & ast 433 | return result 434 | } 435 | 436 | // ================================================================ 437 | // Interface declarations 438 | 439 | // ParseInterfaceDecl parses BSV declaration: 'interface ... endinterface' 440 | // Precondition: "interface" keyword already consumed 441 | func ParseInterfaceDecl (lexer *Lexer) (*AstIfcDecl) { 442 | ifc := ParseTypedefDefinee (lexer) 443 | ast := AstIfcDecl {Ifc: ifc} 444 | 445 | skipPunctuationMust (lexer, ";") 446 | 447 | for { 448 | if skipKeywordOpt (lexer, "endinterface") { break } 449 | 450 | if skipPunctuationOpt (lexer, "(*") { 451 | ast.SubIfcOrMethodDecls = append (ast.SubIfcOrMethodDecls, ParseAttrInstance (lexer)) 452 | 453 | } else if skipKeywordOpt (lexer, "interface") { 454 | // Parse a sub-interface decl: starts with "interface" 455 | var x AstIfcDeclSubIfcDecl 456 | x.SubIfcType = ParseTypeExpr (lexer) 457 | x.SubIfcName = ParseIde (lexer) 458 | ast.SubIfcOrMethodDecls = append (ast.SubIfcOrMethodDecls, & x) 459 | skipPunctuationMust (lexer, ";") 460 | } else { 461 | // Parse a method decl if starts with "method" 462 | var x AstIfcDeclMethodDecl 463 | skipKeywordMust (lexer, "method") 464 | x.ReturnType = ParseTypeExpr (lexer) 465 | x.MethodName = ParseIde (lexer) 466 | rparenFound := skipPunctuationOpt (lexer, "(") 467 | if rparenFound { 468 | for { 469 | isCloseParen := skipPunctuationOpt (lexer, ")") 470 | if isCloseParen { break } 471 | 472 | argType := ParseTypeExpr (lexer) 473 | argName := ParseIde (lexer) 474 | x.ArgTypes = append (x.ArgTypes, argType) 475 | x.ArgNames = append (x.ArgNames, argName) 476 | if ! TokenIsSpecificPunctuation (lexer, ")") { 477 | skipPunctuationMust (lexer, ",") 478 | } 479 | } 480 | } 481 | ast.SubIfcOrMethodDecls = append (ast.SubIfcOrMethodDecls, & x) 482 | skipPunctuationMust (lexer, ";") 483 | } 484 | } 485 | return & ast 486 | } 487 | 488 | // ================================================================ 489 | // Parse 'instance ... endinstance' 490 | 491 | // ParseInstance parses BSV declaration: 'instance ... endinstance' 492 | // Current token is 'instance' 493 | func ParseInstance (lexer *Lexer) (AST) { 494 | debugPrint (os.Stdout, "ParseInstance ... ", nil, "\n") 495 | 496 | var astInstance AstInstance 497 | 498 | // Skip past 'instance' keyword 499 | GetToken (lexer) 500 | 501 | astInstance.TypeclassIde = ParseConstIde (lexer) 502 | skipPunctuationMust (lexer, "#") 503 | skipPunctuationMust (lexer, "(") 504 | for { 505 | if TokenIsSpecificPunctuation (lexer, ")") { break } 506 | astInstance.Types = append (astInstance.Types, ParseTypeExpr (lexer)) 507 | if ! TokenIsSpecificPunctuation (lexer, ")") { 508 | skipPunctuationMust (lexer, ",") 509 | } 510 | } 511 | GetToken (lexer) 512 | 513 | if TokenIsKeyword (lexer, "provisos") { 514 | astInstance.Provisos = ParseProvisos (lexer) 515 | } 516 | 517 | skipPunctuationMust (lexer, ";") 518 | 519 | for { 520 | if TokenIsKeyword (lexer, "endinstance") { break } 521 | stmt := ParseStmt (lexer) 522 | astInstance.Stmts = append (astInstance.Stmts, stmt) 523 | } 524 | GetToken (lexer) // 'endinstance' 525 | 526 | if skipPunctuationOpt (lexer, ":") { 527 | x := ParseConstIde (lexer) 528 | AST_pp (os.Stdout, "", x) 529 | // TODO: should be same as astInstance.TypeclassIde 530 | } 531 | 532 | return & astInstance 533 | } 534 | 535 | // ================================================================ 536 | // Parse command line 537 | 538 | var pp bool = false 539 | 540 | func printUsage () () { 541 | fmt.Fprintf (os.Stdout, "Usage:\n") 542 | fmt.Fprintf (os.Stdout, " %s filename\n", os.Args [0]) 543 | fmt.Fprintf (os.Stdout, "\n") 544 | fmt.Fprintf (os.Stdout, "Macro-def: -Dmacro For `ifdefs in the source file\n") 545 | fmt.Fprintf (os.Stdout, "Flag: -debug Print a verbose trace of the recursive descent parse\n") 546 | fmt.Fprintf (os.Stdout, "Flag: -pp Pretty-print the final AST for the file\n") 547 | } 548 | 549 | // ParseCommandLine parses a command line: sequence of -DFOO defs and a filename. 550 | // Returns the -D defs in first result, 551 | // and the filename in the second result. 552 | func ParseCommandLine () ([]string, string) { 553 | macros := make ([]string, 0, 0) 554 | inputFilename := "-" 555 | for j := 1; j < len (os.Args); j++ { 556 | arg := os.Args [j] 557 | if (arg == "-h") || (arg == "--help") { 558 | printUsage () 559 | os.Exit (0) 560 | } else if strings.HasPrefix (arg, "-D") { 561 | macros = append (macros, strings.TrimPrefix (arg, "-D")) 562 | } else if arg == "-debug" { 563 | debug = true 564 | 565 | } else if arg == "-pp" { 566 | pp = true 567 | 568 | } else if inputFilename == "-" { 569 | inputFilename = arg 570 | } else { 571 | fmt.Fprintf (os.Stderr, "ERROR: ParseCommandLine: Junk in command line: %s\n", arg) 572 | os.Exit (1) 573 | } 574 | } 575 | 576 | // Debugging 577 | if false { 578 | for j, macro := range (macros) { 579 | if (j == 0) { fmt.Fprintf (os.Stdout, "Macros\n") } 580 | fmt.Fprintf (os.Stdout, " %s\n", macro) 581 | } 582 | fmt.Fprintf (os.Stdout, "Input filename: %q\n", inputFilename) 583 | } 584 | 585 | return macros, inputFilename 586 | } 587 | 588 | // ================================================================ 589 | 590 | // TestParser parses a file and prints the ASTs to stdout. 591 | func TestParser () () { 592 | macros, inputFilename := ParseCommandLine () 593 | 594 | // Create a lexer for the file 595 | lexer := NewLexer (inputFilename, macros, nil) 596 | GetToken (lexer) 597 | 598 | // Parse the file 599 | ast := ParsePackage (lexer) 600 | 601 | // Pretty-print the AST 602 | if pp { 603 | AST_pp (os.Stdout, "", ast) 604 | } else { 605 | fmt.Fprintf (os.Stdout, "Ok\n") 606 | } 607 | } 608 | -------------------------------------------------------------------------------- /lexer.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Rishiyur Nikhil and Bluespec, Inc. All Rights Reserved. 2 | 3 | // Lexical analyzer for BSV files 4 | 5 | package goParseBSV 6 | 7 | import ( 8 | "bufio" // Buffered I/O 9 | "fmt" 10 | "os" 11 | "io" 12 | "strings" 13 | "strconv" 14 | ) 15 | 16 | // ================================================================ 17 | // Tokens 18 | 19 | // The different types of lexical tokens. 20 | const ( 21 | TokNone uint = iota 22 | TokEof 23 | TokKeyword 24 | TokIde // identifiers 25 | TokInteger 26 | TokString 27 | TokOther 28 | TokUnknown 29 | ) 30 | 31 | type Token struct { 32 | TokType uint 33 | StringVal string 34 | IntVal int64 // original string is in 'StringVal' field 35 | IntWidth int // BSV bit-width; -1 for unspecified 36 | LineNum int 37 | Column int 38 | } 39 | 40 | func (tok *Token) PrintToken (fout *os.File) { 41 | fmt.Fprintf (fout, "Token [L %0d C %0d]: ", tok.LineNum, tok.Column) 42 | switch tok.TokType { 43 | case TokNone: fmt.Fprintf (fout, "NONE") 44 | case TokEof: fmt.Fprintf (fout, "EOF") 45 | case TokKeyword: fmt.Fprintf (fout, "KEYWORD %s", tok.StringVal) 46 | case TokIde: fmt.Fprintf (fout, "IDENTIFIER %s", tok.StringVal) 47 | case TokInteger: { 48 | fmt.Fprintf (fout, "INTEGER %q (= %d)", tok.StringVal, tok.IntVal) 49 | if (tok.IntWidth == -1) { 50 | fmt.Fprintf (fout, " Integer") 51 | } else { 52 | fmt.Fprintf (fout, " #(%0d)", tok.IntWidth) 53 | } 54 | } 55 | case TokString: fmt.Fprintf (fout, "STRING %q", tok.StringVal) 56 | case TokOther: fmt.Fprintf (fout, "OTHER %s", tok.StringVal); 57 | case TokUnknown: fmt.Fprintf (fout, "UNKNOWN %s", tok.StringVal) 58 | default: fmt.Fprintf (fout, "", tok.TokType) 59 | } 60 | } 61 | 62 | // Lexer objects encapsulate a lexer for a source file. 63 | type Lexer struct { 64 | ifdefMacros [] string // for this file and nested `includes 65 | filename string 66 | reader *bufio.Reader 67 | prevLexer *Lexer // stack of nested `includes 68 | 69 | ch byte 70 | line string 71 | lineNum int 72 | colNum int 73 | ifdefStack [] ifdefStackElem // for nested `ifdef/ifndef-`elsif-`else-`endif 74 | 75 | Tracefile *os.File // for debugging 76 | Token *Token 77 | } 78 | 79 | func printLocation (fout *os.File, lexer *Lexer, prefix string) () { 80 | fmt.Fprintf (fout, "%sFile %s [L %0d C %0d]\n", prefix, lexer.filename, lexer.lineNum, lexer.colNum) 81 | fmt.Fprintf (fout, "%sLine: %q\n", prefix, lexer.line) 82 | } 83 | 84 | func (lexer *Lexer) PrintToken (fout *os.File, prefix string) { 85 | fmt.Fprintf (fout, "%sToken: ", prefix) 86 | lexer.Token.PrintToken (fout) 87 | fmt.Fprintf (fout, "\n") 88 | fmt.Fprintf (fout, "%sLine: %q\n", prefix, lexer.line) 89 | fmt.Fprintf (fout, "%sFile: %s\n", prefix, lexer.filename) 90 | } 91 | 92 | // NewLexer creates a new lexer for the given file, macro defs, and debug trace file. 93 | func NewLexer (inputFilename string, macros []string, ftrace *os.File) (*Lexer) { 94 | // Open the file for reading 95 | var fin *os.File 96 | var err error 97 | if inputFilename == "-" { 98 | fin = os.Stdin 99 | fmt.Fprintf (os.Stdout, "Taking input from stdin\n") 100 | } else { 101 | fin, err = os.Open (inputFilename) 102 | if err != nil { 103 | fmt.Fprintf (os.Stderr, "ERROR: unable to open file %q for reading\n", inputFilename) 104 | fmt.Fprintf (os.Stderr, "%v\n", err) 105 | os.Exit (1) 106 | } 107 | fmt.Fprintf (os.Stdout, "Taking input from file %q\n", inputFilename) 108 | } 109 | 110 | var lexer = new (Lexer) 111 | lexer.ifdefMacros = macros 112 | lexer.filename = inputFilename 113 | lexer.reader = bufio.NewReader (fin) 114 | lexer.prevLexer = nil 115 | 116 | lexer.ch = ' ' 117 | lexer.line = "" 118 | lexer.lineNum = 0 119 | lexer.colNum = 0 120 | lexer.ifdefStack = make ([] ifdefStackElem, 1, 10) 121 | lexer.ifdefStack [0] = ifdefStackElem {ifClauseSatisfied: true, 122 | thisClauseActive: true, 123 | inElse: false, 124 | currentMacro: "ALWAYS_DEFINED"} 125 | getchar (lexer, true) // get the first char; eof is ok (file may be empty) 126 | 127 | lexer.Tracefile = ftrace // output all tokens to this file 128 | lexer.Token = nil 129 | return lexer 130 | } 131 | 132 | // pushLexer is called on a `include. 133 | // Creates a new lexer and pushes the current lexer on the prevLexer stack. 134 | func pushLexer (inputFilename string, lexer *Lexer) () { 135 | 136 | // Open the file for reading 137 | fin, err := os.Open (inputFilename) 138 | if err != nil { 139 | fmt.Fprintf (os.Stderr, "Unable to open file %s for reading\n", inputFilename) 140 | fmt.Fprintf (os.Stderr, "%v\n", err) 141 | os.Exit (1) 142 | } 143 | fmt.Fprintf (os.Stdout, "Taking input from included file: %q\n", inputFilename) 144 | 145 | var pushedLexer = new (Lexer) 146 | 147 | // Copy contents of lexer into pushedLexer 148 | *pushedLexer = *lexer 149 | 150 | // Make lexer point at pushedLexer, i.e., it's a new top-of-stack of lexers 151 | lexer.prevLexer = pushedLexer 152 | 153 | // Re-initialize lexer on the new, included input file 154 | lexer.filename = inputFilename 155 | lexer.reader = bufio.NewReader (fin) 156 | 157 | lexer.ch = ' ' 158 | lexer.line = "" 159 | lexer.lineNum = 0 160 | lexer.colNum = 0 161 | lexer.ifdefStack = make ([] ifdefStackElem, 1, 10) 162 | lexer.ifdefStack [0] = ifdefStackElem {ifClauseSatisfied: true, 163 | thisClauseActive: true, 164 | inElse: false, 165 | currentMacro: "ALWAYS_DEFINED"} 166 | getchar (lexer, true) // get the first char; eof is ok (file may be empty) 167 | 168 | lexer.Token = nil 169 | } 170 | 171 | // popLexer is called at the end of a `include'd file. 172 | // Restores the lexer to the `include parent from the prevLexer stack. 173 | func popLexer (lexer *Lexer) () { 174 | pushedLexer := lexer.prevLexer 175 | fmt.Fprintf (os.Stdout, "Finished included file : %q\n", lexer.filename) 176 | fmt.Fprintf (os.Stdout, "Resuming input from file: %q\n", pushedLexer.filename) 177 | 178 | // Copy contents of pushedLexer into lexer 179 | *lexer = *pushedLexer 180 | 181 | // We drop pushedLexer on the floor. 182 | // lexer.prevLexer now points to pushedLexer.prevLexer 183 | } 184 | 185 | // The ifdef stack is an array of ifdefStackElem's. 186 | type ifdefStackElem struct { 187 | ifClauseSatisfied bool // If any ifdef/ifndef/elsif was satisfied (therefore skip remaining elsif/endif) 188 | thisClauseActive bool // If lines in current arm are active or to be skipped 189 | inElse bool // If in else arm (therefore illegal to see elsif of else) 190 | currentMacro string // for error messages: current macro of ifdef/ifndef/elsif 191 | } 192 | 193 | func pushIfdefStack (lexer *Lexer, elem ifdefStackElem) () { 194 | lexer.ifdefStack = append (lexer.ifdefStack, elem) 195 | // fmt.Fprintf (os.Stdout, "pushIfdefStack: new stack is %v\n", lexer.ifdefStack) 196 | } 197 | 198 | func topOfIfdefStack (lexer *Lexer) (ifdefStackElem) { 199 | return lexer.ifdefStack [len (lexer.ifdefStack) - 1] 200 | } 201 | 202 | func popIfdefStack (lexer *Lexer) () { 203 | depth := len (lexer.ifdefStack) 204 | if (depth == 1) { 205 | fmt.Fprintf (os.Stderr, "ERROR: ifdef-stack underflow (too many endifs?)\n") 206 | printLocation (os.Stderr, lexer, "") 207 | os.Exit (1) 208 | } 209 | lexer.ifdefStack = lexer.ifdefStack [:depth - 1] 210 | // fmt.Fprintf (os.Stdout, "popIfdefStack: new stack %v\n", lexer.ifdefStack) 211 | } 212 | 213 | // readline reads an input line. 214 | // Error if eofOk is false, or inside an `ifdef...`endif. 215 | func readline (lexer *Lexer, eofOk bool) { 216 | lexer.line = "" 217 | for { 218 | nextCh, err := lexer.reader.ReadByte () 219 | if err == io.EOF { 220 | if len (lexer.ifdefStack) > 1 { 221 | fmt.Fprintf (os.Stderr, "ERROR: EOF while inside the following ifdefs/ifndefs\n") 222 | for j := len (lexer.ifdefStack) - 1; j > 0; j-- { 223 | fmt.Fprintf (os.Stderr, " %s\n", lexer.ifdefStack [j].currentMacro) 224 | } 225 | os.Exit (1) 226 | } 227 | if ! eofOk { 228 | fmt.Fprintf (os.Stderr, "ERROR: Unexpected EOF\n") 229 | printLocation (os.Stderr, lexer, "") 230 | os.Exit (1) 231 | } 232 | // If in a nested `include, pop to the parent lexer. 233 | if lexer.prevLexer != nil { 234 | popLexer (lexer) 235 | lexer.line = "" 236 | continue 237 | } 238 | lexer.line = "\0000" 239 | break 240 | } else if nextCh == '\n' { 241 | lexer.line += string (nextCh) 242 | break 243 | } else { 244 | lexer.line += string (nextCh) 245 | } 246 | } 247 | lexer.lineNum++ 248 | lexer.colNum = 1 249 | } 250 | 251 | // checkIncludeCycle checks if there is a cycle in the `include chain, 252 | // i.e., whether a file is effectively including itself through a chain of includes. 253 | func checkIncludeCycle (includeFilename string, lexer *Lexer) (bool) { 254 | if lexer == nil { 255 | return false 256 | } else if includeFilename == lexer.filename { 257 | fmt.Fprintf (os.Stderr, "ERROR: Chain of `includes cycles back; ignoring this final `include\n") 258 | fmt.Fprintf (os.Stderr, " ") 259 | printLocation (os.Stderr, lexer, "") 260 | return true 261 | } else { 262 | b := checkIncludeCycle (includeFilename, lexer.prevLexer) 263 | if b { 264 | fmt.Fprintf (os.Stderr, " ") 265 | printLocation (os.Stderr, lexer, "") 266 | } 267 | return b 268 | } 269 | } 270 | 271 | // processIncludeLine handles lines that begin with `include. 272 | // Push a new lexer for the included file. 273 | func processIncludeLine (lexer *Lexer) () { 274 | trimmedLine := strings.TrimSpace (lexer.line) 275 | 276 | // Skip whitespace after `include 277 | var j int = len ("`include") 278 | for { 279 | if j >= len (trimmedLine) { 280 | fmt.Fprintf (os.Stderr, "ERROR: `include line syntax\n") 281 | printLocation (os.Stderr, lexer, "") 282 | os.Exit (1) 283 | } 284 | if (trimmedLine [j] != ' ') { break } 285 | j++ 286 | } 287 | // Check for opening quote or < 288 | if (trimmedLine [j] != '"') && (trimmedLine [j] != '<') { 289 | fmt.Fprintf (os.Stderr, "ERROR: `include line syntax\n") 290 | printLocation (os.Stderr, lexer, "") 291 | os.Exit (1) 292 | } 293 | openQuote := trimmedLine [j] 294 | j++ 295 | // Collect the file name 296 | includeFilename := "" 297 | for { 298 | if j >= len (trimmedLine) { 299 | fmt.Fprintf (os.Stderr, "ERROR: `include line syntax\n") 300 | printLocation (os.Stderr, lexer, "") 301 | os.Exit (1) 302 | } 303 | if (openQuote == '"') && (trimmedLine [j] == '"') { break } 304 | if (openQuote == '<') && (trimmedLine [j] == '>') { break } 305 | includeFilename += string (trimmedLine [j]) 306 | j++ 307 | } 308 | lexer.colNum = len (lexer.line) 309 | 310 | isCyclic := checkIncludeCycle (includeFilename, lexer) 311 | if isCyclic { 312 | return // Ignore this include line 313 | } 314 | 315 | pushLexer (includeFilename, lexer) 316 | } 317 | 318 | // getMacroFromCurrentLine processes a line starting with `ifdef, `ifndef or `elsif. 319 | // Return the macro name that follows it. 320 | func getMacroFromCurrentLine (lexer *Lexer) (string) { 321 | fields := strings.Fields (lexer.line) 322 | if len (fields) != 2 { 323 | fmt.Fprintf (os.Stderr, "ERROR: Macro line (ifdef/ifndef/elseif) not well formed\n") 324 | fmt.Fprintf (os.Stderr, " Must be followed by just the macro name\n") 325 | printLocation (os.Stderr, lexer, "") 326 | os.Exit (1) 327 | } 328 | return fields [1] 329 | } 330 | 331 | // macroIsDefined processes a line starting with `ifdef, `ifndef or `elsif. 332 | // Check if the macro that follows is defined. 333 | func macroIsDefined (lexer *Lexer) (bool) { 334 | thisMacro := getMacroFromCurrentLine (lexer) 335 | defined := false 336 | for _, definedMacro := range lexer.ifdefMacros { 337 | if definedMacro == thisMacro { 338 | defined = true 339 | break 340 | } 341 | } 342 | return defined 343 | } 344 | 345 | // readLineModuloIfdefs reads a line that is active w.r.t., `ifdef/ifndef-`elsif-`else-`endif. 346 | func readLineModuloIfdefs (lexer *Lexer, eofOk bool) () { 347 | for { 348 | readline (lexer, eofOk) 349 | trimmedLine := strings.TrimSpace (lexer.line) 350 | 351 | if strings.HasPrefix (trimmedLine, "`ifdef") { 352 | elemTop := topOfIfdefStack (lexer) 353 | macro := getMacroFromCurrentLine (lexer) 354 | if macroIsDefined (lexer) { 355 | pushIfdefStack (lexer, ifdefStackElem {true, elemTop.thisClauseActive, false, macro}) 356 | } else { 357 | pushIfdefStack (lexer, ifdefStackElem {false, false, false, macro}) 358 | } 359 | 360 | } else if strings.HasPrefix (trimmedLine, "`ifndef") { 361 | elemTop := topOfIfdefStack (lexer) 362 | macro := getMacroFromCurrentLine (lexer) 363 | if macroIsDefined (lexer) { 364 | pushIfdefStack (lexer, ifdefStackElem {false, false, false, macro}) 365 | } else { 366 | pushIfdefStack (lexer, ifdefStackElem {true, elemTop.thisClauseActive, false, macro}) 367 | } 368 | 369 | } else if strings.HasPrefix (trimmedLine, "`elsif") { 370 | elemTop := topOfIfdefStack (lexer) 371 | if elemTop.inElse { 372 | fmt.Fprintf (os.Stderr, "ERROR: 'elsif' not allowed after 'else'\n") 373 | printLocation (os.Stderr, lexer, "") 374 | os.Exit (1) 375 | } 376 | macro := getMacroFromCurrentLine (lexer) 377 | popIfdefStack (lexer) 378 | elemNext := topOfIfdefStack (lexer) 379 | if elemTop.ifClauseSatisfied { 380 | pushIfdefStack (lexer, ifdefStackElem {true, false, false, macro}) 381 | } else if macroIsDefined (lexer) { 382 | pushIfdefStack (lexer, ifdefStackElem {true, elemNext.thisClauseActive, false, macro}) 383 | } else { 384 | pushIfdefStack (lexer, ifdefStackElem {false, false, false, macro}) 385 | } 386 | 387 | } else if strings.HasPrefix (trimmedLine, "`else") { 388 | elemTop := topOfIfdefStack (lexer) 389 | if elemTop.inElse { 390 | fmt.Fprintf (os.Stderr, "ERROR: 'else' not allowed after 'else'\n") 391 | printLocation (os.Stderr, lexer, "") 392 | os.Exit (1) 393 | } 394 | macro := elemTop.currentMacro 395 | popIfdefStack (lexer) 396 | elemNext := topOfIfdefStack (lexer) 397 | if elemTop.ifClauseSatisfied { 398 | pushIfdefStack (lexer, ifdefStackElem {true, false, true, macro}) 399 | } else { 400 | pushIfdefStack (lexer, ifdefStackElem {true, elemNext.thisClauseActive, true, macro}) 401 | } 402 | 403 | } else if strings.HasPrefix (trimmedLine, "`endif") { 404 | popIfdefStack (lexer) 405 | 406 | } else if topOfIfdefStack (lexer).thisClauseActive { 407 | if strings.HasPrefix (trimmedLine, "`include") { 408 | processIncludeLine (lexer) 409 | } else { 410 | // An actual source line 411 | return 412 | } 413 | } else { 414 | // ! thisClauseActive; skip this line 415 | } 416 | } 417 | } 418 | 419 | // getchar gets the next char from the input file, modulo ifdefs. 420 | func getchar (lexer *Lexer, eofOk bool) () { 421 | lexer.colNum++ 422 | 423 | // if gone past end of last line, read in another line 424 | if lexer.colNum > len (lexer.line) { 425 | readLineModuloIfdefs (lexer, eofOk) 426 | } 427 | lexer.ch = lexer.line [lexer.colNum - 1] 428 | } 429 | 430 | // getDigitString parses a digit string in base 2, 8, 10 or 16 431 | // returning original string in lexer.Token.StringVal, 432 | // value in IntVal 433 | func getDigitString (lexer *Lexer, base int) () { 434 | // Invariant: lexer.ch is first digit (or spacer '_') of a digit string 435 | lexer.Token.StringVal += string (lexer.ch) 436 | buffer := "" 437 | if (lexer.ch != '_') { 438 | buffer += string (lexer.ch) 439 | } 440 | getchar (lexer, true) 441 | for { 442 | if lexer.ch == '_' { 443 | lexer.Token.StringVal += string (lexer.ch) 444 | getchar (lexer, true) 445 | } else if (base == 10) && ByteIsDigit (lexer.ch) { 446 | lexer.Token.StringVal += string (lexer.ch) 447 | buffer += string (lexer.ch) 448 | getchar (lexer, true) 449 | } else if (base == 16) && ByteIsHexdigit (lexer.ch) { 450 | lexer.Token.StringVal += string (lexer.ch) 451 | buffer += string (lexer.ch) 452 | getchar (lexer, true) 453 | } else if (base == 8) && ByteIsOctdigit (lexer.ch) { 454 | lexer.Token.StringVal += string (lexer.ch) 455 | buffer += string (lexer.ch) 456 | getchar (lexer, true) 457 | } else if (base == 2) && ByteIsBindigit (lexer.ch) { 458 | lexer.Token.StringVal += string (lexer.ch) 459 | buffer += string (lexer.ch) 460 | getchar (lexer, true) 461 | } else { 462 | break 463 | } 464 | } 465 | n, err := strconv.ParseInt (buffer, base, 64) 466 | if (err != nil) { 467 | fmt.Fprintf (os.Stderr, "ERROR: lexer: parsing integer\n") 468 | printLocation (os.Stderr, lexer, "") 469 | fmt.Fprintf (os.Stderr, " buffer %q base %0d\n", buffer, base) 470 | os.Exit (1) 471 | } else { 472 | lexer.Token.IntVal = n 473 | } 474 | } 475 | 476 | // GetToken gets the next token from a file, modulo ifdefs. 477 | func GetToken (lexer *Lexer) () { 478 | if ((lexer.Token != nil) && (lexer.Token.TokType == TokEof)) { 479 | return 480 | } 481 | 482 | // Skip whitespace and comments 483 | for { 484 | if ByteIsWhitespace (lexer.ch) { 485 | getchar (lexer, true) 486 | } else if (lexer.ch == 0) { 487 | break 488 | } else if lexer.ch == '/' { 489 | lexer.Token = new (Token) 490 | lexer.Token.TokType = TokOther 491 | lexer.Token.StringVal = "/" 492 | lexer.Token.LineNum = lexer.lineNum 493 | lexer.Token.Column = lexer.colNum 494 | getchar (lexer, false) 495 | if lexer.ch == '/' { 496 | // Start of a '//' comment 497 | for { 498 | getchar (lexer, true) 499 | if (lexer.ch == 0) { 500 | fmt.Printf ("WARNING: '//' comment ends in end-of-file\n") 501 | printLocation (os.Stdout, lexer, "") 502 | break 503 | } else if lexer.ch == '\n' { 504 | getchar (lexer, true) 505 | break 506 | } 507 | } 508 | } else if lexer.ch == '*' { 509 | // Start of a '/*' comment 510 | for { 511 | getchar (lexer, true) 512 | if lexer.ch == 0 { 513 | fmt.Printf ("WARNING: '/*' comment ends in end-of-file\n") 514 | printLocation (os.Stdout, lexer, "") 515 | break 516 | } else if lexer.ch == '*' { 517 | getchar (lexer, false) 518 | if lexer.ch == '/' { 519 | getchar (lexer, true) 520 | break 521 | } 522 | } 523 | } 524 | } else { 525 | return 526 | } 527 | } else { 528 | break 529 | } 530 | } 531 | // Invariant: lexer.ch has been read, is not whitespace, is not in comment 532 | 533 | lexer.Token = new (Token) 534 | lexer.Token.StringVal = "" 535 | lexer.Token.LineNum = lexer.lineNum 536 | lexer.Token.Column = lexer.colNum 537 | 538 | switch { 539 | case lexer.ch == 0: { 540 | lexer.Token.TokType = TokEof 541 | } 542 | case ByteIsAlpha (lexer.ch) || (lexer.ch == '$') || (lexer.ch == '_'): { 543 | for { 544 | lexer.Token.StringVal += string (lexer.ch) 545 | getchar (lexer, true) 546 | if ByteIsAlpha (lexer.ch) || 547 | (lexer.ch == '_') || 548 | ByteIsDigit (lexer.ch) { 549 | } else { 550 | break 551 | } 552 | } 553 | if isKeyword (lexer.Token.StringVal) { 554 | lexer.Token.TokType = TokKeyword 555 | } else { 556 | lexer.Token.TokType = TokIde 557 | } 558 | } 559 | case ByteIsDigit (lexer.ch): { 560 | lexer.Token.TokType = TokInteger 561 | lexer.Token.IntWidth = -1 // unspecified width 562 | getDigitString (lexer, 10) 563 | 564 | if lexer.ch == '\'' { 565 | lexer.Token.StringVal += string (lexer.ch) 566 | lexer.Token.IntWidth = int (lexer.Token.IntVal) 567 | 568 | getchar (lexer, false) 569 | var base int 570 | switch lexer.ch { 571 | case 'h': { base = 16 } 572 | case 'd': { base = 10 } 573 | case 'o': { base = 8 } 574 | case 'b': { base = 2 } 575 | default: { 576 | fmt.Fprintf (os.Stderr, "Unrecognized base %c in integer literal\n", lexer.ch) 577 | printLocation (os.Stderr, lexer, "") 578 | os.Exit (1) 579 | } 580 | } 581 | lexer.Token.StringVal += string (lexer.ch) 582 | 583 | getchar (lexer, true) 584 | getDigitString (lexer, base) 585 | } 586 | } 587 | case lexer.ch == '\'': { 588 | lexer.Token.TokType = TokInteger 589 | lexer.Token.IntWidth = -1 // unspecified width 590 | lexer.Token.StringVal = string (lexer.ch) 591 | 592 | getchar (lexer, false) 593 | 594 | if lexer.ch == '1' { 595 | lexer.Token.StringVal += string (lexer.ch) 596 | lexer.Token.IntVal = -1 597 | getchar (lexer, true) 598 | } else { 599 | var base int 600 | switch lexer.ch { 601 | case 'h': { base = 16 } 602 | case 'd': { base = 10 } 603 | case 'o': { base = 8 } 604 | case 'b': { base = 2 } 605 | default: { 606 | fmt.Fprintf (os.Stderr, "Unrecognized base %c in integer literal\n", lexer.ch) 607 | printLocation (os.Stderr, lexer, "") 608 | os.Exit (1) 609 | } 610 | } 611 | lexer.Token.StringVal += string (lexer.ch) 612 | 613 | getchar (lexer, true) 614 | getDigitString (lexer, base) 615 | } 616 | } 617 | case lexer.ch == '"': { 618 | lexer.Token.TokType = TokString 619 | lexer.Token.StringVal = "" 620 | getchar (lexer, false) 621 | for { 622 | if lexer.ch == '"' { 623 | getchar (lexer, true) 624 | break 625 | } else if lexer.ch == '\\' { 626 | getchar (lexer, false) 627 | switch lexer.ch { 628 | case '\\', '"': { lexer.Token.StringVal += string (lexer.ch) } 629 | case 'n': { lexer.Token.StringVal += "\n" } 630 | case 'r': { lexer.Token.StringVal += "\r" } 631 | case 't': { lexer.Token.StringVal += "\t" } 632 | default: { 633 | fmt.Fprintf (os.Stdout, 634 | "WARNING: Unrecognized \\-escaped char '%c' (= %0d), taking it as-is\n", 635 | lexer.ch, 636 | lexer.ch) 637 | printLocation (os.Stdout, lexer, "") 638 | lexer.Token.StringVal += string (lexer.ch) 639 | } 640 | } 641 | getchar (lexer, false) 642 | } else { 643 | lexer.Token.StringVal += string (lexer.ch) 644 | getchar (lexer, false) 645 | } 646 | } 647 | } 648 | case strings.IndexByte ("{})[]#$;,`'?-+%", lexer.ch) != -1: { 649 | lexer.Token.TokType = TokOther 650 | lexer.Token.StringVal = string (lexer.ch) 651 | getchar (lexer, true) 652 | } 653 | case lexer.ch == '.': { 654 | lexer.Token.TokType = TokOther 655 | lexer.Token.StringVal = "." 656 | getchar (lexer, true) 657 | if lexer.ch == '.' { 658 | lexer.Token.StringVal = ".." 659 | getchar (lexer, true) 660 | } 661 | } 662 | case lexer.ch == '*': { 663 | lexer.Token.TokType = TokOther 664 | lexer.Token.StringVal = "*" 665 | getchar (lexer, true) 666 | if lexer.ch == '*' { 667 | lexer.Token.StringVal = "**" 668 | getchar (lexer, true) 669 | } else if lexer.ch == ')' { 670 | lexer.Token.StringVal = "*)" 671 | getchar (lexer, true) 672 | } 673 | } 674 | case lexer.ch == ':': { 675 | lexer.Token.TokType = TokOther 676 | lexer.Token.StringVal = ":" 677 | getchar (lexer, true) 678 | if lexer.ch == ':' { 679 | lexer.Token.StringVal = "::" 680 | getchar (lexer, true) 681 | } 682 | } 683 | case lexer.ch == '(': { 684 | lexer.Token.TokType = TokOther 685 | lexer.Token.StringVal = "(" 686 | getchar (lexer, true) 687 | if lexer.ch == '*' { 688 | lexer.Token.StringVal = "(*" 689 | getchar (lexer, true) 690 | } 691 | } 692 | case lexer.ch == '<': { 693 | lexer.Token.TokType = TokOther 694 | lexer.Token.StringVal = "<" 695 | getchar (lexer, true) 696 | if lexer.ch == '<' { 697 | lexer.Token.StringVal = "<<" 698 | getchar (lexer, true) 699 | } else if lexer.ch == '=' { 700 | lexer.Token.StringVal = "<=" 701 | getchar (lexer, true) 702 | } else if lexer.ch == '-' { 703 | lexer.Token.StringVal = "<-" 704 | getchar (lexer, true) 705 | } 706 | } 707 | case lexer.ch == '>': { 708 | lexer.Token.TokType = TokOther 709 | lexer.Token.StringVal = ">" 710 | getchar (lexer, true) 711 | if lexer.ch == '=' { 712 | lexer.Token.StringVal = ">=" 713 | getchar (lexer, true) 714 | } else if lexer.ch == '>' { 715 | lexer.Token.StringVal = ">>" 716 | getchar (lexer, true) 717 | } 718 | } 719 | case lexer.ch == '=': { 720 | lexer.Token.TokType = TokOther 721 | lexer.Token.StringVal = "=" 722 | getchar (lexer, true) 723 | if lexer.ch == '=' { 724 | lexer.Token.StringVal = "==" 725 | getchar (lexer, true) 726 | } 727 | } 728 | case lexer.ch == '!': { 729 | lexer.Token.TokType = TokOther 730 | lexer.Token.StringVal = "!" 731 | getchar (lexer, true) 732 | if lexer.ch == '=' { 733 | lexer.Token.StringVal = "!=" 734 | getchar (lexer, true) 735 | } 736 | } 737 | case lexer.ch == '&': { 738 | lexer.Token.TokType = TokOther 739 | lexer.Token.StringVal = "&" 740 | getchar (lexer, true) 741 | if lexer.ch == '&' { 742 | lexer.Token.StringVal = "&&" 743 | getchar (lexer, true) 744 | if lexer.ch == '&' { 745 | lexer.Token.StringVal = "&&&" 746 | getchar (lexer, true) 747 | } 748 | } 749 | } 750 | case lexer.ch == '|': { 751 | lexer.Token.TokType = TokOther 752 | lexer.Token.StringVal = "|" 753 | getchar (lexer, true) 754 | if lexer.ch == '|' { 755 | lexer.Token.StringVal = "||" 756 | getchar (lexer, true) 757 | } 758 | } 759 | case lexer.ch == '^': { 760 | lexer.Token.TokType = TokOther 761 | lexer.Token.StringVal = "^" 762 | getchar (lexer, true) 763 | if lexer.ch == '~' { 764 | lexer.Token.StringVal = "^~" 765 | getchar (lexer, true) 766 | } 767 | } 768 | case lexer.ch == '~': { 769 | lexer.Token.TokType = TokOther 770 | lexer.Token.StringVal = "~" 771 | getchar (lexer, true) 772 | if lexer.ch == '|' { 773 | lexer.Token.StringVal = "~|" 774 | getchar (lexer, true) 775 | } else if lexer.ch == '&' { 776 | lexer.Token.StringVal = "~&" 777 | getchar (lexer, true) 778 | } else if lexer.ch == '^' { 779 | lexer.Token.StringVal = "~^" 780 | getchar (lexer, true) 781 | } 782 | } 783 | default: { 784 | fmt.Fprintf (os.Stderr, "ERROR: lexer: unrecognized character '%c' = (%0d)\n", lexer.ch, lexer.ch) 785 | printLocation (os.Stderr, lexer, "") 786 | os.Exit (1) 787 | } 788 | } 789 | 790 | // Debugging 791 | if lexer.Tracefile != nil { 792 | lexer.Token.PrintToken (lexer.Tracefile) 793 | fmt.Fprintf (lexer.Tracefile, "\n") 794 | } 795 | } 796 | 797 | // ================================================================ 798 | // Keywords 799 | // TODO: sort alphabetically and use binary search 800 | 801 | 802 | var keywordTable = [...] string { 803 | "BVI", 804 | "C", 805 | "CF", 806 | "E", 807 | "SB", 808 | "SBR", 809 | "action", 810 | "actionvalue", 811 | "ancestor", 812 | "begin", 813 | "break", 814 | "case", 815 | "clocked_by", 816 | "continue", 817 | "default", 818 | "default_clock", 819 | "default_reset", 820 | "dependencies", 821 | "deriving", 822 | "determines", 823 | "else", 824 | "enable", 825 | "end", 826 | "endaction", 827 | "endactionvalue", 828 | "endcase", 829 | "endfunction", 830 | "endinstance", 831 | "endinterface", 832 | "endmethod", 833 | "endmodule", 834 | "endpackage", 835 | "endpar", 836 | "endrule", 837 | "endrules", 838 | "endseq", 839 | "endtypeclass", 840 | "enum", 841 | "export", 842 | "for", 843 | "function", 844 | "if", 845 | "ifc_inout", 846 | "import", 847 | "inout", 848 | "input_clock", 849 | "input_reset", 850 | "instance", 851 | "interface", 852 | "let", 853 | "match", 854 | "matches", 855 | "method", 856 | "module", 857 | "numeric", 858 | "output_clock", 859 | "output_reset", 860 | "package", 861 | "parameter", 862 | "par", 863 | "path", 864 | "port", 865 | "provisos", 866 | "ready", 867 | "reset_by", 868 | "return", 869 | "rule", 870 | "rules", 871 | "same_family", 872 | "schedule", 873 | "seq", 874 | "struct", 875 | "tagged", 876 | "type", 877 | "typeclass", 878 | "typedef", 879 | "union", 880 | "void", 881 | "while" } 882 | 883 | func isKeyword (s string) (bool) { 884 | for _, kw := range (keywordTable) { 885 | if s == kw { return true } 886 | } 887 | return false 888 | } 889 | 890 | func MatchingEndKeyword (kw string) (string) { 891 | var endkw string 892 | switch (kw) { 893 | case "action": endkw = "endaction" 894 | case "actionvalue": endkw = "endactionvalue" 895 | case "begin": endkw = "end" 896 | case "case": endkw = "endcase" 897 | case "function": endkw = "endfunction" 898 | case "instance": endkw = "endinstance" 899 | case "interface": endkw = "endinterface" 900 | case "method": endkw = "endmethod" 901 | case "module": endkw = "endmodule" 902 | case "package": endkw = "endpackage" 903 | case "rule": endkw = "endrule" 904 | case "rules": endkw = "endrules" 905 | case "typeclass": endkw = "endtypeclass" 906 | default: { 907 | fmt.Fprintf (os.Stderr, "ERROR: MatchingEndKeyword (\"%s\"): unknown begin-keyword\n", kw) 908 | os.Exit (1) 909 | } 910 | } 911 | return endkw 912 | } 913 | 914 | // ================================================================ 915 | 916 | // TestLexer read tokens from a file and print them to stdout. 917 | func TestLexer () () { 918 | macros, inputFilename := ParseCommandLine () 919 | lexer := NewLexer (inputFilename, macros, nil) 920 | for { 921 | GetToken (lexer) 922 | var tok *Token = lexer.Token 923 | tok.PrintToken (os.Stdout) 924 | fmt.Printf ("\n") 925 | if tok.TokType == TokEof { break } 926 | } 927 | } 928 | 929 | // ================================================================ 930 | -------------------------------------------------------------------------------- /grammar.txt: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Rishiyur Nikhil and Bluespec, Inc. All Rights Reserved. 2 | 3 | This is a grammar of BSV, extracted out of the BSV Reference Guide. 4 | The BSV Reference Guide provides BNF for the grammar, scattered across 5 | the various sections of the document. 6 | 7 | This document collects all those BNF rules and simplifies them and 8 | reorganizes them somewhat. At the bottom of this document are some 9 | notes about differences (mostly small and benign) with the grammar in 10 | the Reference Guide. 11 | 12 | // ================================================================ 13 | Meta notation: 14 | 15 | Terminal 'x' i.e., with single quotes 16 | Non-terminal x i.e., without single quotes 17 | Alternatives x | y 18 | Optional item [ x ] 19 | 0 or more occurrences { x } 20 | Comments // comment 21 | 22 | // ================================================================ 23 | // Packages 24 | 25 | package :: ::= 'package' packageIde ';' 26 | { exportDecl } 27 | { importDecl } 28 | { packageStmt } 29 | 'endpackage' [ ':' packageIde ] 30 | 31 | exportDecl ::= 'export' exportItem { ',' exportItem } ';' 32 | exportItem ::= identifier [ '(' '..' ')' ] 33 | | Identifier [ '(' '..' ')' ] 34 | | packageIde '::' '*' 35 | 36 | importDecl ::= 'import' importItem { ',' importItem } ';' 37 | importItem ::= packageIde '::' '*' 38 | 39 | packageStmt ::= interfaceDecl 40 | | typeDef 41 | | typeclassDef 42 | | typeclassInstanceDef 43 | | externModuleImport 44 | | externCImport // #5 45 | | varDecl 46 | | functionDef 47 | | moduleDef // #3 48 | 49 | packageIde ::= Identifier 50 | 51 | // ================================================================ 52 | // Statement: Interface Declarations 53 | 54 | interfaceDecl ::= [ attributeInstances ] 55 | 'interface' typeDefType ';' 56 | { interfaceMemberDecl } 57 | 'endinterface' [ ':' typeIde ] 58 | 59 | interfaceMemberDecl ::= methodProto | subinterfaceDecl 60 | 61 | methodProto ::= [ attributeInstances ] 62 | 'method' type identifier [ '(' methodProtoFormals ')' ] ';' #20 63 | methodProtoFormals ::= methodProtoFormal { ',' methodProtoFormal } 64 | methodProtoFormal ::= [ attributeInstances ] type identifier 65 | 66 | subinterfaceDecl ::= [ attributeInstances ] 67 | 'interface' type identifier; #30 68 | 69 | // ================================================================ 70 | // Typedefs 71 | 72 | typeDef ::= typedefSynonym 73 | | typedefEnum 74 | | typedefStruct 75 | | typedefTaggedUnion 76 | 77 | typeDefType ::= typeIde [ typeFormals ] 78 | typeFormals ::= '#' '(' typeFormal { ',' typeFormal } ')' 79 | typeFormal ::= [ 'numeric' ] 'type' typeIde 80 | 81 | // Synonym typedefs 82 | typedefSynonym ::= 'typedef' type typeDefType ';' 83 | 84 | // Enum typedefs 85 | typedefEnum ::= 'typedef' 'enum' { typedefEnumElements } Identifier [ derives ] ';' 86 | typedefEnumElements ::= typedefEnumElement { ',' typedefEnumElement } 87 | typedefEnumElement ::= Identifier [ '=' intLiteral ] 88 | | Identifier '[' intLiteral ']' [ '=' intLiteral ] 89 | | Identifier '[' intLiteral ':' intLiteral ']' [ '=' intLiteral ] 90 | 91 | // Struct and taggedunion typedefs 92 | typedefStruct ::= 'typedef' 'struct' '{' 93 | { structMember } 94 | '}' typeDefType [ derives ] ';' 95 | 96 | typedefTaggedUnion ::= 'typedef' 'union' 'tagged' '{' 97 | { unionMember } 98 | '}' typeDefType [ derives ] ';' 99 | 100 | structMember ::= type identifier ';' 101 | | subUnion identifier ';' 102 | 103 | unionMember ::= type Identifier ';' 104 | | subStruct Identifier ';' 105 | | subUnion Identifier ';' 106 | | 'void' Identifier ';' 107 | 108 | subStruct ::= 'struct' '{' 109 | { structMember } 110 | '}' 111 | subUnion ::= 'union' 'tagged' '{' 112 | { unionMember } 113 | '}' 114 | 115 | derives ::= 'deriving' '(' typeclassIde { ',' typeclassIde } ')' 116 | 117 | // ================================================================ 118 | // Variable declarations and initialization 119 | 120 | varDecl ::= type varInit { ',' varInit } ';' 121 | | type identifier '<-' expression ';' 122 | | 'let' identifier '=' expression ';' 123 | | 'let' identifier '<-' expression ';' 124 | | 'match' pattern '=' expression ';' 125 | 126 | varInit ::= identifier [ arrayDims ] [ '=' expression ] 127 | arrayDims ::= '[' expression ']' { '[' expression ']' } 128 | 129 | // ================================================================ 130 | // Typeclass definitions 131 | 132 | typeclassDef ::= 'typeclass' typeclassIde typeFormals [ provisos ] [ typedepends ] ';' 133 | { overloadedDef } 134 | 'endtypeclass' [ ':' typeclassIde ] 135 | typeclassIde ::= Identifier 136 | 137 | typeFormals ::= '#' '(' typeFormal { ',' typeFormal } ')' 138 | typeFormal ::= [ 'numeric' ] 'type' typeIde 139 | typedepends ::= 'dependencies' '(' typedepend { ',' typedepend } ')' 140 | typedepend ::= typelist 'determines' typelist 141 | typelist ::= typeIde 142 | | '(' typeIde { ',' typeIde } ')' 143 | overloadedDef ::= functionProto 144 | | moduleProto #13 145 | | varDecl 146 | 147 | // ================================================================ 148 | // Typeclass instance definitions 149 | 150 | typeclassInstanceDef ::= 'instance' typeclassIde '#' '(' type { ',' type } ')' [ provisos ] ';' 151 | { varAssign ';' | functionDef | moduleDef } 152 | 'endinstance' [ ':' typeclassIde ] 153 | 154 | // ================================================================ 155 | // Module Declarations 156 | 157 | moduleDef ::= [ attributeInstances ] 158 | moduleProto 159 | { moduleStmt } 160 | 'endmodule' [ ':' identifier ] 161 | moduleProto ::= 'module' [ '[' type ']' ] identifier 162 | [ moduleFormalParams ] 163 | '(' [ moduleFormalArgs ] ')' [ provisos ] ';' 164 | moduleFormalParams ::= '#' '(' moduleFormalParam { ',' moduleFormalParam } ')' 165 | moduleFormalParam ::= [ attributeInstances ] [ 'parameter' ] type identifier 166 | moduleFormalArgs ::= [ attributeInstances ] type 167 | | [ attributeInstances ] type identifier 168 | { ',' [ attributeInstances ] type identifier } 169 | moduleStmt ::= moduleInst #15 170 | | methodDef 171 | | subinterfaceDef 172 | | rule 173 | | Stmt 174 | 175 | // ---------------- 176 | // 5.4.1: Short form instantiation 177 | 178 | moduleInst ::= [ attributeInstances ] 179 | | type identifier '<-' moduleApp ';' 180 | moduleApp ::= identifier 181 | [ '(' moduleActualParamArg { ',' moduleActualParamArg } ')' ] #40 182 | 183 | moduleActualParamArg ::= expression 184 | | 'clocked_by' expression 185 | | 'reset_by' expression 186 | 187 | // ---------------- 188 | // 5.4.2: Long form instantiation 189 | // NOTE: Not supported in goParseBSV. Obsolete (still exists in some very old BSV code). 190 | 191 | moduleInst ::= [ attributeInstances ] 192 | type identifier '(' ')' ';' 193 | moduleApp2 identifier [ '(' moduleActualArgs ')' ] ';' #50 194 | moduleApp2 ::= identifier [ '#' '(' moduleActualParam { ',' moduleActualParam } ')' ] 195 | moduleActualParam ::= expression 196 | moduleActualArgs ::= moduleActualArg { ',' moduleActualArg } 197 | moduleActualArg ::= expression 198 | | 'clocked_by' expression 199 | | 'reset_by' expression 200 | 201 | // ---------------- 202 | // 5.5 Interface definition (definition of methods) 203 | 204 | methodDef ::= 'method' [ type ] identifier [ '(' [ methodFormals ] ')' ] [ implicitCond ] ';' #60 205 | functionBody 206 | 'endmethod' [ ':' identifier ] 207 | methodFormals ::= methodFormal { ',' methodFormal } 208 | methodFormal ::= [ type ] identifier 209 | implicitCond ::= 'if' '(' condPredicate ')' 210 | 211 | // 5.5.2 Definition of subinterfaces 212 | 213 | subinterfaceDef ::= 'interface' Identifier identifier ';' 214 | { interfaceStmt } 215 | 'endinterface' [ ':' identifier ] 216 | interfaceStmt ::= methodDef 217 | | subinterfaceDef 218 | 219 | // 5.5.3 Definition of methods and subinterfaces by assignment 220 | 221 | methodDef ::= 'method' [ type ] identifier '(' methodFormals ')' [ implicitCond ] 222 | '=' expression ';' #80 223 | subinterfaceDef ::= 'interface' [ type ] identifier '=' expression ';' 224 | 225 | // ---------------- 226 | // 5.6 Rules in module definitions 227 | 228 | rule ::= [ attributeInstances ] 229 | 'rule' identifier [ ruleCond ] ';' 230 | ruleBody 231 | 'endrule' [ ':' identifier ] 232 | ruleCond ::= '(' condPredicate ')' 233 | ruleBody ::= { actionStmt } 234 | 235 | // ================================================================ 236 | // Function definition 237 | 238 | functionDef ::= [ attributeInstances ] 239 | functionProto 240 | { Stmt } 241 | 'endfunction' [ ':' identifier ] 242 | | functionProto '=' expression ';' #84 243 | 244 | functionProto ::= 'function' type identifier [ '(' functionFormals ')' ] [ provisos ] ';' #85 245 | functionFormals ::= functionFormal { ',' functionFormal } 246 | functionFormal ::= type identifier 247 | 248 | // ================================================================ 249 | // Importing C functions 250 | 251 | externCImport ::= 'import' '"BDPI"' [ identifier '=' ] 252 | 'function' type identifier '(' [ CFuncArgs ] ')' [ provisos ] ';' 253 | 254 | CFuncArgs ::= CFuncArg { ',' CFuncArg } 255 | CFuncArg ::= type [ identifier ] 256 | 257 | // ================================================================ 258 | // Variable assignment (for variables already declared) 259 | 260 | varAssign ::= lValue '=' expression ';' 261 | | identifier '<-' expression ';' 262 | 263 | lValue ::= identifier 264 | | lValue '.' identifier 265 | | lValue '[' expression ']' 266 | | lValue '[' expression ':' expression ']' 267 | 268 | // ================================================================ 269 | // Types 270 | 271 | type ::= typePrimary 272 | | typePrimary ( type { ',' type } ) // #10; OBSOLETE 273 | 274 | typePrimary ::= typeIde [ '#' '(' type { ',' type } ')' ] // #11 275 | | typeNat 276 | | 'bit' [ typeNat ':' typeNat ] 277 | 278 | typeIde ::= Identifier 279 | | 'SizeOf' 280 | 281 | typeNat ::= decDigits 282 | 283 | // ================================================================ 284 | // Expressions 285 | 286 | expression ::= condExpr 287 | | operatorExpr 288 | | exprPrimary 289 | 290 | condExpr ::= condPredicate '?' expression ':' expression 291 | 292 | operatorExpr ::= unop expression 293 | | expression binop expression 294 | 295 | // The following operators are in order of decreasing precedence 296 | unop ::= '+' | '-' | '!' | '~' 297 | | '&' 298 | | '~&' 299 | | '|' 300 | | '~|' 301 | | '^' 302 | | '^~' | '~^' 303 | binop ::= '*' | '/' | '%' 304 | | '+' | '-' 305 | | '<<' | '>>' 306 | | '<=' | '>=' | '<' | '>' 307 | | '==' | '!=' 308 | | '&' 309 | | '^' 310 | | '^~' | '~^' 311 | | '|' 312 | | '&&' 313 | | '||' 314 | 315 | exprPrimary ::= '(' expression ')' 316 | | exprPrimary '.' identifier 317 | | identifier 318 | | intLiteral 319 | | realLiteral 320 | | stringLiteral 321 | | '?' 322 | | 'valueof' '(' type ')' 323 | | 'valueOf' '(' type ')' 324 | | 'return' expression ';' 325 | | bitConcat 326 | | bitSelect 327 | | functionCall 328 | | methodCall 329 | | typeAssertion 330 | | structExpr 331 | | taggedUnionExpr 332 | | interfaceExpr 333 | | rulesExpr 334 | | beginEndBlock 335 | | actionBlock 336 | | actionValueBlock 337 | | seqFsmStmt 338 | | parFsmStmt 339 | 340 | bitConcat ::= '{' expression { ',' expression } '}' 341 | bitSelect ::= exprPrimary '[' expression [ ':' expression ] ']' 342 | 343 | functionCall ::= exprPrimary [ '(' [ expression { ',' expression } ] ')' ] 344 | methodCall ::= exprPrimary '.' identifier [ '(' [ expression { ',' expression } ] ')' ] 345 | 346 | typeAssertion ::= type '’' bitConcat 347 | | type '’' '(' expression ')' 348 | 349 | structExpr ::= Identifier '{' memberBind { ',' memberBind } '}' 350 | taggedUnionExpr ::= 'tagged' Identifier '{' memberBind { ',' memberBind } '}' 351 | | 'tagged' Identifier exprPrimary 352 | memberBind ::= identifier ':' expression 353 | 354 | interfaceExpr ::= 'interface' Identifier ';' 355 | { interfaceStmt } 356 | 'endinterface' [ ':' Identifier ] 357 | interfaceStmt ::= methodDef 358 | | subinterfaceDef 359 | | expressionStmt 360 | 361 | rulesExpr ::= [ attributeInstances ] 362 | 'rules' [ ':' identifier ] 363 | rulesStmt 364 | 'endrules' [ ':' identifier ] 365 | rulesStmt ::= rule 366 | | expressionStmt 367 | 368 | // ---------------- 369 | // Blocks: begin-end, action-endaction, actionvalue-endactionvalue 370 | // and bodies of functions, methods and rules 371 | 372 | BeginEndBlock ::= 'begin' [ ':' identifier ] 373 | { Stmt } 374 | expression 375 | 'end' [ ':' identifier ] 376 | 377 | actionBlock ::= 'action' [ ':' identifier ] 378 | { Stmt } 379 | 'endaction' [ ':' identifier ] 380 | 381 | actionValueBlock ::= 'actionvalue' [ ':' identifier ] 382 | { Stmt } 383 | 'endactionvalue' [ ':' identifier ] 384 | 385 | regWrite ::= expression '<=' expression #90 386 | 387 | // ---------------- 388 | // General statements 389 | 390 | Stmt ::= expression 391 | | varDecl 392 | | varAssign 393 | | functionDef 394 | | moduleDef 395 | | BeginEndBlock 396 | | If 397 | | Case 398 | | For 399 | | While 400 | 401 | // ---------------- 402 | // Conditionals 403 | 404 | If ::= 'if' '(' condPredicate ')' 405 | Stmt 406 | [ 'else' 407 | Stmt ] 408 | 409 | Case ::= 'case' '(' expression ')' 410 | { CaseItem } 411 | [ DefaultItem ] 412 | 'endcase' 413 | 414 | | 'case' '(' expression ')' 'matches' 415 | { CasePatItem } 416 | [ DefaultItem ] 417 | 'endcase' 418 | CaseItem ::= expression { , expression } ':' Stmt 419 | CasePatItem ::= pattern { '&&&' expression } ':' Stmt 420 | DefaultItem ::= 'default' [ ':' ] Stmt 421 | 422 | // ---------------- 423 | // Static loops 424 | 425 | While ::= 'while' '(' expression ')' 426 | Stmt 427 | For ::= 'for' '(' forInit ';' forTest ';' forIncr ')' 428 | Stmt 429 | forInit ::= forOldInit | forNewInit 430 | forOldInit ::= simpleVarAssign { ',' simpleVarAssign } 431 | simpleVarAssign ::= identifier '=' expression 432 | forNewInit ::= type identifier '=' expression { ',' simpleVarDeclAssign } 433 | simpleVarDeclAssign ::= [ type ] identifier '=' expression 434 | forTest ::= expression 435 | forIncr ::= varIncr { ',' varIncr } 436 | varIncr ::= identifier = expression 437 | 438 | // ================================================================ 439 | // Cond predicates occur in method def implicit conditions, rule 440 | // conditions, if expressions, pattern-matching case expressions, ... 441 | 442 | condPredicate ::= exprOrCondPattern { '&&&' exprOrCondPattern } 443 | exprOrCondPattern ::= expression 444 | | expression 'matches' pattern 445 | 446 | // ================================================================ 447 | // Patterns occur in condPredicates 448 | 449 | pattern ::= '.' identifier 450 | | '.*' 451 | | constantPattern 452 | | taggedUnionPattern 453 | | structPattern 454 | | tuplePattern 455 | 456 | constantPattern ::= intLiteral 457 | | realLiteral 458 | | stringLiteral 459 | | Identifier 460 | 461 | taggedUnionPattern ::= 'tagged' Identifier [ pattern ] 462 | structPattern ::= 'tagged' Identifier '{' identifier ':' pattern { ',' identifier ':' pattern } '}' 463 | tuplePattern ::= '{' pattern { ',' pattern } '}' 464 | 465 | // ================================================================ 466 | // Attributes 467 | 468 | attributeInstances ::= attributeInstance 469 | { attributeInstance } 470 | attributeInstance ::= '(*' attrSpec { ',' attrSpec } '*)' 471 | attrSpec ::= attrName [ '=' expression ] 472 | attrName ::= identifier 473 | | Identifier 474 | 475 | // ================================================================ 476 | // Provisos 477 | 478 | provisos ::= 'provisos' '(' proviso { ',' proviso } ')' 479 | proviso ::= Identifier '#' '(' type { ',' type } ')' 480 | 481 | // ================================================================ 482 | // StmtFSM 483 | 484 | fsmStmt ::= exprFsmStmt 485 | | seqFsmStmt 486 | | parFsmStmt 487 | | ifFsmStmt 488 | | whileFsmStmt 489 | | repeatFsmStmt 490 | | forFsmStmt 491 | | returnFsmStmt 492 | 493 | exprFsmStmt ::= regWrite ';' 494 | | expression ';' 495 | 496 | seqFsmStmt ::= 'seq' fsmStmt { fsmStmt } 'endseq' 497 | 498 | parFsmStmt ::= 'par' fsmStmt { fsmStmt } 'endpar' 499 | 500 | ifFsmStmt ::= 'if' expression fsmStmt 501 | [ 'else' fsmStmt ] 502 | 503 | returnFsmStmt ::= 'return' ';' 504 | 505 | whileFsmStmt ::= 'while' '(' expression ')' 506 | loopBodyFsmStmt 507 | 508 | forFsmStmt ::= 'for' '(' fsmStmt ';' expression ';' fsmStmt ')' 509 | loopBodyFsmStmt 510 | 511 | repeatFsmStmt ::= 'repeat' '(' expression ')' 512 | loopBodyFsmStmt 513 | 514 | loopBodyFsmStmt ::= fsmStmt 515 | | 'break' ';' 516 | | 'continue' ';' 517 | 518 | // ================================================================ 519 | // KEYWORDS (cannot be used as identifiers) 520 | 521 | Action 522 | ActionValue 523 | BVI 524 | C 525 | CF 526 | E 527 | SB 528 | SBR 529 | action endaction 530 | actionvalue endactionvalue 531 | ancestor 532 | begin 533 | bit 534 | case endcase 535 | clocked_by 536 | default 537 | default_clock 538 | default_reset 539 | dependencies 540 | deriving 541 | determines 542 | e 543 | else 544 | enable 545 | end 546 | enum 547 | export 548 | for 549 | function endfunction 550 | if 551 | ifc_inout 552 | import 553 | inout 554 | input_clock 555 | input_reset 556 | instance endinstance 557 | interface endinterface 558 | let 559 | match 560 | matches 561 | method endmethod 562 | module endmodule 563 | numeric 564 | output_clock 565 | output_reset 566 | package endpackage 567 | parameter 568 | path 569 | port 570 | provisos 571 | ready 572 | reset_by 573 | return 574 | rule endrule 575 | rules endrules 576 | same_family 577 | schedule 578 | struct 579 | tagged 580 | type 581 | typeclass endtypeclass 582 | typedef 583 | union 584 | valueOf 585 | valueof 586 | void 587 | while 588 | 589 | // ================================================================ 590 | // System task/function names 591 | 592 | displayTaskName ::= '$display' | '$displayb' | '$displayo' | '$displayh' 593 | | '$write' | '$writeb' | '$writeo' | '$writeh' 594 | | '$format' 595 | | '$fopen' | '$fclose' 596 | | '$fdisplay' | '$fdisplayb' | '$fdisplayo' | '$fdisplayh' 597 | | '$fwrite' | '$fwriteb' | '$fwriteo' | '$fwriteh' 598 | | '$swrite' | '$swriteb' | '$swriteo' | '$swriteh' | '$sformat' 599 | | '$swriteAV' | '$swritebAV' | '$swriteoAV' | '$swritehAV' | '$sformatAV' 600 | | '$fgetc' | '$fungetc' 601 | | '$fflush' 602 | | '$finish' 603 | | '$stop' 604 | | '$dumpvars' | '$dumpon' | '$dumpoff' 605 | | '$time' | '$stime' 606 | | '$realtobits' 607 | | '$bitstoreal' 608 | | '$test$plusargs' 609 | 610 | // ================================================================ 611 | // DIFFERENCES FROM GRAMMAR IN REFERENCE GUIDE 612 | 613 | #3 Sec.3, p.21, fourth line of production for packageStmt 614 | A 'varAssign' should not be allowed here? Must have a type decl or let? 615 | 616 | #5 Sec.3, p.21, production for 'packageStmt' 617 | Missing an alternative: 'externCImport' 618 | 619 | #10 Sec.4, p.23, second production for 'type' 620 | Really? we have a typePrimary (t,..,t) for a Function type? 621 | Why don't we just have 'Function #(ResultType, Arg1Type, ..., ArgNType)'? 622 | 623 | #11 Sec.4, p.23, production for 'typePrimary' 624 | Missing alternative: typevar 625 | 626 | #13 Sec.14.1.2, p.122, production for 'overloadedDef' 627 | Missing: 'moduleProto' 628 | 629 | #15 Sec.5.4, p.34, production for 'moduleStmt' 630 | Sec 9.6, p.71, production for 'actionStmt' 631 | Sec 9.7, p.71, production for 'actionValueStmt' 632 | Sec 12.8, p.92, all the productions in this section 633 | 634 | Removed productions for everything in 12.8 ('systemTaskStmt', 635 | 'systemTaskCall', 'displayTaskName', 'fileTaskName', 636 | 'stringTaskName', 'stringAVTaskName'. Grammatically, these are 637 | just function application where the function happens to be a 638 | system task. 639 | 640 | #20 Sec.5.2, p.30, second line of production for 'methodProto' 641 | The parens around formals are shown compulsory, but they should 642 | be optional (inside the grammar square brackets) 643 | 644 | #30 Sec.5.2.1, p.31, second line of production for 'subinterfaceDecl' 645 | 'interface typeDefType' should be 'interface type identifier' 646 | Note: 'typeDefType' is a definee, and contain a 'kind' annocation 647 | ('numeric type' or 'type') 648 | whereas a 'type' is a type expression, not a definee. 649 | 650 | #40 Sec.5.4.1, p.34, second line of production for 'moduleApp' 651 | The parens around args are shown compulsory, but they should 652 | be optional (inside the grammar square brackets) 653 | 654 | #50 Sec.5.4.2, p.35, third line of production for 'moduleInst' 655 | The parens around args are shown compulsory, but they should 656 | be optional (inside the grammar square brackets) 657 | 658 | #60 Sec.5.5, p.36, first line of production for 'methodDef' 659 | Grammar shows compulsory parens and at least one 'methodFormal'. 660 | Parens should be optional, and zero or more 'methodFormal's ares ok 661 | 662 | #70 Sec.5.5.2, p.39, third line of production for 'interfaceStmt' 663 | Really? Can be an expressionStmt? I never use this. 664 | 665 | #80 Sec.5.5.3, p.39, production for 'methodDef' 666 | The parens around formals are shown compulsory, but they should 667 | be optional (inside the grammar square brackets) 668 | 669 | #84 Sec 8.8.1, p.67, production for 'functionProto' 670 | Actually this should be: 671 | 'functionDef ::= functionProto = expression;' 672 | 673 | #85 Sec.8.8, p.66, production for 'functionProto' 674 | The parens around formals are shown compulsory, but they should 675 | be optional (inside the grammar square brackets) 676 | 677 | 678 | #90 Sec.8.4, p.60, second line of production for 'regWrite' 679 | Unclear why we require parentheses. Any expr that evals to a Reg #(t) should be ok. 680 | 681 | Sec.8.4.1, 8.4.2, 8.4.3 (array-selection, bit-selection and struct member selection) 682 | are redundant. The unifying way of saying this is to talk about register lvalues: 683 | regWrite := regLValue <= expression 684 | regLValue := expression 685 | | regLValue arrayIndexes 686 | | regLValue [ expression : expression ] 687 | | regLValue '.' identifier 688 | where 'expression' evaluates to Reg #(t) and the array-select, 689 | bit-select and member-select express a partial update. Note: 690 | Since 'expression' itself can contain array-selects and 691 | member-selects, it may be ambiguous where we place the boundary 692 | between the 'expression' and the 'regLValue'. 693 | We can resolve this as the sub-expr that has type 'Reg #(t)', 694 | at which point we insert the ._write() 695 | 696 | // ================================================================ 697 | -------------------------------------------------------------------------------- /backend_pp.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Rishiyur Nikhil and Bluespec, Inc. All Rights Reserved. 2 | 3 | // This is back-end processor of ASTs created by goParseBSV, a parser 4 | // for BSV files. 5 | 6 | // Specifically, this is a pretty printer that traverses an AST 7 | // and prints it out with reasonable indentation etc. 8 | 9 | // More generally, it provides an example of how to structure other 10 | // back-ends that traverse the AST and do some processing on them. 11 | // The key idea is that we define a local interface ast_pp with a 12 | // method pp. Then we define the pp method for each AST type AstFoo. 13 | // To process recursive components of interface type AST 14 | 15 | package goParseBSV 16 | 17 | import ( 18 | // golang packages 19 | "fmt" 20 | "os" 21 | ) 22 | 23 | // ================================================================ 24 | // Top-level function exported out of this file 25 | 26 | func AST_pp (fout *os.File, indent string, ast AST) () { 27 | conv (ast).pp (fout, indent) 28 | } 29 | 30 | // ================================================================ 31 | // Each kind of AST has its own struct definition 32 | // They are all 'union'd via the AST interface 33 | 34 | // AST is the generic type of Abstract Syntax Trees 35 | // PP_AST2 is the method to pretty print an AST 36 | type ast_pp_ifc interface { 37 | pp (fout *os.File, indent string) 38 | } 39 | 40 | // Convert an AST to an ast_pp_ifc 41 | func conv (ast AST) (ast_pp_ifc) { 42 | ast_pp := ast.(ast_pp_ifc) 43 | return ast_pp 44 | } 45 | 46 | // ================================================================ 47 | // Items that occur in many parts of the grammar 48 | 49 | // Ides 50 | func (ast *AstIde) pp (fout *os.File, indent string) { 51 | fmt.Fprintf (fout, "%s", ast.LeafValue.StringVal) 52 | } 53 | 54 | // Attribute instances 55 | func (ast *AstAttrInstance) pp (fout *os.File, indent string) { 56 | fmt.Fprintf (fout, "(* ") 57 | for j, ide := range (ast.Ides) { 58 | if (j != 0) { fmt.Fprintf (fout, ", ") } 59 | ide.pp (fout, indent) 60 | if ast.Vals [j] != nil { 61 | fmt.Fprintf (fout, " = ") 62 | conv (ast.Vals [j]).pp (fout, indent) 63 | } 64 | } 65 | fmt.Fprintf (fout, " *)") 66 | } 67 | 68 | // ================================================================ 69 | // ASTs for types 70 | 71 | // AstTypeNum is a BSV numeric type, e.g., "16" 72 | func (ast *AstTypeNum) pp (fout *os.File, indent string) { 73 | fmt.Fprintf (fout, "%d", ast.LeafValue.IntVal) 74 | } 75 | 76 | // AstTypeVar is a BSV type variable (identifier with lowercase first letter) 77 | // E.g., "t" 78 | func (ast *AstTypeVar) pp (fout *os.File, indent string) { 79 | fmt.Fprintf (fout, "%s", ast.LeafValue.StringVal) 80 | } 81 | 82 | // AstTypeConstructed is a BSV "TypeConstructor #(typeExpr, ..., typeExpr)" 83 | func (x AstTypeConstructed) pp (fout *os.File, indent string) { 84 | fmt.Fprintf (fout, "%s", x.Constructor.LeafValue.StringVal) 85 | if len (x.Args) > 0 { 86 | fmt.Fprintf (fout, " #(") 87 | for j, arg := range (x.Args) { 88 | if j != 0 { fmt.Fprintf (fout, ", ") } 89 | conv (arg).pp (fout, indent) 90 | } 91 | fmt.Fprintf (fout, ")") 92 | } 93 | } 94 | 95 | // AstTypedefDefinedAsStruct is a BSV "struct { type field; ... ; type field }" 96 | func (ast *AstTypedefDefinedAsStruct) pp (fout *os.File, indent string) () { 97 | fmt.Fprintf (fout, "struct {") 98 | indent2 := indent + " " 99 | for j, memberName := range (ast.StructMemberNames) { 100 | if (j > 0) { fmt.Fprintf (fout, indent2) } 101 | fieldType := ast.StructMemberTypes [j] 102 | conv (fieldType).pp (fout, indent) 103 | fmt.Fprintf (fout, " ") 104 | memberName.pp (fout, indent) 105 | fmt.Fprintf (fout, ";\n") 106 | } 107 | fmt.Fprintf (fout, indent) 108 | fmt.Fprintf (fout, "}") 109 | } 110 | 111 | // AstTypedefDefinedAsTaggedUnion is a BSV "union tagged { type field; ... ; type field }" 112 | func (ast *AstTypedefDefinedAsTaggedUnion) pp (fout *os.File, indent string) () { 113 | fmt.Fprintf (fout, "union tagged {\n") 114 | indent2 := indent + " " 115 | for j, memberName := range (ast.TaggedUnionMemberNames) { 116 | if (j > 0) { fmt.Fprintf (fout, indent2) } 117 | fieldType := ast.TaggedUnionMemberTypes [j] 118 | conv (fieldType).pp (fout, indent) 119 | fmt.Fprintf (fout, " ") 120 | memberName.pp (fout, indent) 121 | fmt.Fprintf (fout, ";\n") 122 | } 123 | fmt.Fprintf (fout, indent) 124 | fmt.Fprintf (fout, "}") 125 | } 126 | 127 | // AstTypedefDefinedAsEnum is a BSV "enum { label [=val], ... , label [=val] }" 128 | func (ast *AstTypedefDefinedAsEnum) pp (fout *os.File, indent string) () { 129 | fmt.Fprintf (fout, "enum {") 130 | indent2 := indent + " " 131 | for j, typedefEnumElement := range (ast.TypedefEnumElements) { 132 | if (j > 0) { fmt.Fprintf (fout, indent2) } 133 | typedefEnumElement.pp (fout, indent) 134 | if ast.TypedefEnumVals [j] != nil { 135 | fmt.Fprintf (fout, " = ") 136 | conv (ast.TypedefEnumVals [j]).pp (fout, indent2) 137 | } 138 | if j < (len (ast.TypedefEnumElements) - 1) { 139 | fmt.Fprintf (fout, ",\n") 140 | } else { 141 | fmt.Fprintf (fout, "}") 142 | } 143 | } 144 | } 145 | 146 | // AstTypedefDefinee is the new type being defined in a typedef: Type #(typeFormal,...,typeFormal) 147 | // where each typeformal is "type typevar" or "numeric type typevar" 148 | func (ast *AstTypedefDefinee) pp (fout *os.File, indent string) { 149 | conv (ast.TypeConstructor).pp (fout, indent) 150 | if len (ast.TypeFormals) != 0 { 151 | fmt.Fprintf (fout, " #(") 152 | for j, formal := range (ast.TypeFormals) { 153 | if (j != 0) { fmt.Fprintf (fout, ", ") } 154 | if ast.TypeFormalKinds [j] == KindNumeric { 155 | fmt.Fprintf (fout, "numeric ") 156 | } 157 | fmt.Fprintf (fout, "type ") 158 | conv (formal).pp (fout, indent) 159 | } 160 | fmt.Fprintf (fout, ")") 161 | } 162 | } 163 | 164 | // ================================================================ 165 | // ASTs for exprs 166 | 167 | // AstNum is a BSV numeric constant 168 | // E.g., 23 169 | func (ast *AstNum) pp (fout *os.File, indent string) { 170 | fmt.Fprintf (fout, "%d", ast.LeafValue.IntVal) 171 | } 172 | 173 | // AstString is a BSV string 174 | // E.g., "x" 175 | func (ast *AstString) pp (fout *os.File, indent string) { 176 | fmt.Fprintf (fout, "\"%s\"", ast.LeafValue.StringVal) 177 | } 178 | 179 | // AstExpr is the parse of a BSV expression applying Expr0 to Exprs 180 | func (ast *AstExpr) pp (fout *os.File, indent string) () { 181 | e0 := ast.Expr0 182 | es := ast.Exprs 183 | 184 | conv (e0).pp (fout, indent) 185 | fmt.Fprintf (fout, " (") 186 | for j,ej := range es { 187 | if (j > 0) { 188 | fmt.Fprintf (fout, ", ") 189 | } 190 | conv (ej).pp (fout, indent) 191 | } 192 | fmt.Fprintf (fout, ")") 193 | } 194 | 195 | // AstCondPredicate is the parse of a condition, in if, while, rule conditions, method conditions, etc. 196 | // i.e., conjunct &&& conjunct &&& ... 197 | func (ast *AstCondPredicate) pp (fout *os.File, indent string) () { 198 | for j, conjunct := range (ast.Conjuncts) { 199 | conv (conjunct).pp (fout, indent) 200 | if j < (len (ast.Conjuncts) - 1) { 201 | fmt.Fprintf (fout, "\n" + indent + "&&& ") 202 | } 203 | } 204 | } 205 | 206 | // AstCondPattern is the parse of: expr matches pattern 207 | func (ast *AstCondPattern) pp (fout *os.File, indent string) () { 208 | conv (ast.Expr).pp (fout, indent) 209 | fmt.Fprintf (fout, " matches ") 210 | conv (ast.Pattern).pp (fout, indent) 211 | } 212 | 213 | // AstBlock is the parse of: 214 | // action ... endaction 215 | // actionvalue ... endactionvalue 216 | // begin ... end 217 | func (ast *AstBlock) pp (fout *os.File, indent string) () { 218 | fmt.Fprintf (fout, ast.BlockKind) 219 | if ast.BlockName != nil { 220 | fmt.Fprintf (fout, ": ") 221 | conv (ast.BlockName).pp (fout, indent) 222 | } 223 | fmt.Fprintf (fout, "\n") 224 | 225 | indent2 := indent + " " 226 | for _, stmt := range (ast.Stmts) { 227 | fmt.Fprintf (fout, indent2) 228 | conv (stmt).pp (fout, indent2) 229 | fmt.Fprintf (fout, "\n") 230 | } 231 | fmt.Fprintf (fout, indent) 232 | fmt.Fprintf (fout, "%s", MatchingEndKeyword (ast.BlockKind)) 233 | } 234 | 235 | // AstReturn is the parse of: return Expr 236 | func (ast *AstReturn) pp (fout *os.File, indent string) () { 237 | fmt.Fprintf (fout, "return ") 238 | conv (ast.Expr).pp (fout, indent) 239 | fmt.Fprintf (fout, ";") 240 | } 241 | 242 | // AstStructExpr is the parse of: Ide {member:Expr, ... } 243 | func (ast *AstStructExpr) pp (fout *os.File, indent string) () { 244 | conv (ast.Name).pp (fout, indent) 245 | fmt.Fprintf (fout, " {\n") 246 | indent2 := indent + " " 247 | for j, name := range (ast.MemberNames) { 248 | fmt.Fprintf (fout, indent2) 249 | conv (name).pp (fout, indent2) 250 | fmt.Fprintf (fout, ":") 251 | conv (ast.MemberExprs [j]).pp (fout, indent2) 252 | if j < (len (ast.MemberNames) - 1) { 253 | fmt.Fprintf (fout, ",\n") 254 | } else { 255 | fmt.Fprintf (fout, "}") 256 | } 257 | } 258 | } 259 | 260 | // AstTaggedUnionExpr is the parse of: tagged Ide Expr 261 | func (ast *AstTaggedUnionExpr) pp (fout *os.File, indent string) () { 262 | fmt.Fprintf (fout, "tagged ") 263 | indent2 := indent + " " 264 | conv (ast.Name).pp (fout, indent) 265 | if ast.Expr != nil { 266 | fmt.Fprintf (fout, "\n" + indent2) 267 | conv (ast.Expr).pp (fout, indent2) 268 | } 269 | } 270 | 271 | // AstCase is the parse of: case ... endcase 272 | func (ast *AstCase) pp (fout *os.File, indent string) () { 273 | fmt.Fprintf (fout, "case (") 274 | conv (ast.Expr).pp (fout, indent) 275 | fmt.Fprintf (fout, ")\n") 276 | indent2 := indent + " " 277 | for j, label := range (ast.Labels) { 278 | fmt.Fprintf (fout, indent2) 279 | conv (label).pp (fout, indent2) 280 | fmt.Fprintf (fout, ":") 281 | conv (ast.Exprs [j]).pp (fout, indent2 + " ") 282 | fmt.Fprintf (fout, ";\n") 283 | } 284 | fmt.Fprintf (fout, indent) 285 | fmt.Fprintf (fout, "endcase") 286 | } 287 | 288 | // AstPatternCase is the parse of: case () matches ... endcase 289 | func (ast *AstPatternCase) pp (fout *os.File, indent string) () { 290 | fmt.Fprintf (fout, "case (") 291 | conv (ast.Expr).pp (fout, indent) 292 | fmt.Fprintf (fout, ")\n") 293 | indent2 := indent + " " 294 | for j, pattern := range (ast.Patterns) { 295 | fmt.Fprintf (fout, indent2) 296 | conv (pattern).pp (fout, indent2) 297 | fmt.Fprintf (fout, ":") 298 | conv (ast.Exprs [j]).pp (fout, indent2 + " ") 299 | fmt.Fprintf (fout, ";\n") 300 | } 301 | fmt.Fprintf (fout, indent) 302 | fmt.Fprintf (fout, "endcase") 303 | } 304 | 305 | // =============================================================== 306 | // ASTs for statements 307 | 308 | // VarDecl is the parse of 'type x1 = e1, x2 = e2, ...;" 309 | func (ast *AstVarDecl) pp (fout *os.File, indent string) () { 310 | conv (ast.Type).pp (fout, indent) 311 | fmt.Fprintf (fout, "\n") 312 | indent2 := indent + " " 313 | for j, varinit := range (ast.VarInits) { 314 | fmt.Fprintf (fout, indent2) 315 | varinit.pp (fout, indent) 316 | if j < (len (ast.VarInits) - 1) { 317 | fmt.Fprintf (fout, ",\n") 318 | } else { 319 | fmt.Fprintf (fout, ";") 320 | } 321 | } 322 | } 323 | 324 | // An Init in a VarDecl, 'xJ = eJ' or 'Ide [e]...[e] = Expr;' 325 | func (ast *AstVarInit) pp (fout *os.File, indent string) () { 326 | conv (ast.Ide).pp (fout, indent) 327 | indent2 := indent + " " 328 | for _, arrayDim := range (ast.ArrayDims) { 329 | fmt.Fprintf (fout, " [") 330 | conv (arrayDim).pp (fout, indent2) 331 | fmt.Fprintf (fout, " ]") 332 | } 333 | if ast.Kind != BindingKindNone { 334 | if ast.Kind == BindingKindEq { 335 | fmt.Fprintf (fout, " = ") 336 | } else { 337 | fmt.Fprintf (fout, " <- ") 338 | } 339 | conv (ast.Init).pp (fout, indent2) 340 | } 341 | } 342 | 343 | // AstLet is the parse of a BSV statement: "let x = e" or "let x <- e" 344 | func (ast *AstLet) pp (fout *os.File, indent string) () { 345 | fmt.Fprintf (fout, "let ") 346 | conv (ast.Ide).pp (fout, indent) 347 | if ast.Kind != BindingKindNone { 348 | indent2 := indent + " " 349 | if ast.Kind == BindingKindEq { 350 | fmt.Fprintf (fout, " = ") 351 | } else { 352 | fmt.Fprintf (fout, " <- ") 353 | } 354 | conv (ast.Expr).pp (fout, indent2) 355 | fmt.Fprintf (fout, ";") 356 | } 357 | } 358 | 359 | // AstMatch is the parse of a BSV statement: "match pattern = e" or "match pattern <- e" 360 | func (ast *AstMatch) pp (fout *os.File, indent string) () { 361 | fmt.Fprintf (fout, "match ") 362 | conv (ast.Pattern).pp (fout, indent) 363 | fmt.Fprintf (fout, " = ") 364 | conv (ast.Expr).pp (fout, indent + " ") 365 | } 366 | 367 | // AstAssign is the parse of a BSV statement: "lhs = e" or "ide <- e" 368 | func (ast *AstAssign) pp (fout *os.File, indent string) () { 369 | conv (ast.Lhs).pp (fout, indent) 370 | if ast.Kind != BindingKindNone { 371 | if ast.Kind == BindingKindEq { 372 | fmt.Fprintf (fout, " = ") 373 | } else { 374 | fmt.Fprintf (fout, " <- ") 375 | } 376 | conv (ast.Rhs).pp (fout, indent + " ") 377 | fmt.Fprintf (fout, ";") 378 | } 379 | } 380 | 381 | // AstRule is the parse of "rule ... endrule" 382 | func (ast *AstRule) pp (fout *os.File, indent string) () { 383 | fmt.Fprintf (fout, "rule ") 384 | conv (ast.Name).pp (fout, indent) 385 | fmt.Fprintf (fout, " (") 386 | if ast.Cond != nil { 387 | conv (ast.Cond).pp (fout, indent) 388 | } 389 | fmt.Fprintf (fout, ");\n") 390 | indent2 := indent + " " 391 | for _, stmt := range (ast.Stmts) { 392 | fmt.Fprintf (fout, indent2) 393 | conv (stmt).pp (fout, indent2) 394 | fmt.Fprintf (fout, "\n") 395 | } 396 | fmt.Fprintf (fout, indent + "endrule") 397 | } 398 | 399 | // AstFunctionProto is the parse of "function type name (type formal, ..., type formal)" 400 | func (ast *AstFunctionProto) pp (fout *os.File, indent string) () { 401 | fmt.Fprintf (fout, "function ") 402 | conv (ast.ResultType).pp (fout, indent) 403 | fmt.Fprintf (fout, " ") 404 | conv (ast.Name).pp (fout, indent) 405 | fmt.Fprintf (fout, " (") 406 | for j, formal := range (ast.Formals) { 407 | if (j != 0) { fmt.Fprintf (fout, ", ") } 408 | conv (ast.FormalTypes [j]).pp (fout, indent) 409 | fmt.Fprintf (fout, " ") 410 | conv (formal).pp (fout, indent) 411 | } 412 | fmt.Fprintf (fout, ")") 413 | } 414 | 415 | // AstFunctionDef is the parse of "function ... endfunction" or "function .... = e" 416 | func (ast *AstFunctionDef) pp (fout *os.File, indent string) () { 417 | ast.Proto.pp (fout, indent) 418 | 419 | if len (ast.Provisos) == 0 { 420 | fmt.Fprintf (fout, ";\n") 421 | } else { 422 | fmt.Fprintf (fout, "\n provisos (") 423 | for j, proviso := range (ast.Provisos) { 424 | if j != 0 { fmt.Fprintf (fout, "\n , ") } 425 | conv (proviso).pp (fout, indent) 426 | } 427 | fmt.Fprintf (fout, ");\n") 428 | } 429 | 430 | indent2 := indent + " " 431 | fmt.Fprintf (fout, indent2) 432 | conv (ast.Body).pp (fout, indent2) 433 | fmt.Fprintf (fout, "\n") 434 | 435 | fmt.Fprintf (fout, indent) 436 | fmt.Fprintf (fout, "endfunction") 437 | } 438 | 439 | // AstMethodDef is the parse of "method ... endmethod" or "method .... = e" 440 | func (ast *AstMethodDef) pp (fout *os.File, indent string) () { 441 | fmt.Fprintf (fout, "method ") 442 | conv (ast.ResultType).pp (fout, indent) 443 | fmt.Fprintf (fout, " ") 444 | conv (ast.Name).pp (fout, indent) 445 | fmt.Fprintf (fout, " (") 446 | for j, formal := range (ast.Formals) { 447 | if (j != 0) { fmt.Fprintf (fout, ", ") } 448 | conv (ast.FormalTypes [j]).pp (fout, indent) 449 | fmt.Fprintf (fout, " ") 450 | conv (formal).pp (fout, indent) 451 | } 452 | if ast.Cond != nil { 453 | fmt.Fprintf (fout, " if (") 454 | conv (ast.Cond).pp (fout, indent) 455 | fmt.Fprintf (fout, ")") 456 | } 457 | fmt.Fprintf (fout, ");\n") 458 | 459 | indent2 := indent + " " 460 | fmt.Fprintf (fout, indent2) 461 | conv (ast.Body).pp (fout, indent2) 462 | fmt.Fprintf (fout, "\n") 463 | 464 | fmt.Fprintf (fout, indent) 465 | fmt.Fprintf (fout, "endmethod") 466 | } 467 | 468 | // AstModuleDef is the parse of "module ... endmodule" 469 | func (ast *AstModuleDef) pp (fout *os.File, indent string) () { 470 | fmt.Fprintf (fout, "module") 471 | if ast.ModuleType != nil { 472 | fmt.Fprintf (fout, " [") 473 | conv (ast.ModuleType).pp (fout, indent) 474 | fmt.Fprintf (fout, "]") 475 | } 476 | 477 | fmt.Fprintf (fout, " ") 478 | conv (ast.Name).pp (fout, indent) 479 | 480 | fmt.Fprintf (fout, " #(") 481 | for j, param := range (ast.FormalParams) { 482 | if (j != 0) { fmt.Fprintf (fout, ", ") } 483 | conv (ast.FormalParamTypes [j]).pp (fout, indent) 484 | fmt.Fprintf (fout, " ") 485 | conv (param).pp (fout, indent) 486 | } 487 | fmt.Fprintf (fout, ")") 488 | 489 | fmt.Fprintf (fout, " (") 490 | conv (ast.IfcType).pp (fout, indent) 491 | fmt.Fprintf (fout, ")") 492 | 493 | 494 | if len (ast.Provisos) == 0 { 495 | fmt.Fprintf (fout, ";\n") 496 | } else { 497 | fmt.Fprintf (fout, "\n provisos (") 498 | for j, proviso := range (ast.Provisos) { 499 | if j != 0 { fmt.Fprintf (fout, "\n , ") } 500 | conv (proviso).pp (fout, indent) 501 | } 502 | fmt.Fprintf (fout, ");\n") 503 | } 504 | 505 | indent2 := indent + " " 506 | for _, stmt := range (ast.Stmts) { 507 | fmt.Fprintf (fout, indent2) 508 | conv (stmt).pp (fout, indent2) 509 | fmt.Fprintf (fout, "\n\n") 510 | } 511 | 512 | fmt.Fprintf (fout, indent + "endmodule") 513 | } 514 | 515 | // AstInterfaceDef is the parse of "interface ... endinterface" within a module 516 | func (ast *AstInterfaceDef) pp (fout *os.File, indent string) () { 517 | fmt.Fprintf (fout, "interface ") 518 | if ast.Type != nil { 519 | conv (ast.Type).pp (fout, indent) 520 | fmt.Fprintf (fout, " ") 521 | } 522 | conv (ast.Name).pp (fout, indent) 523 | fmt.Fprintf (fout, ";\n") 524 | 525 | indent2 := indent + " " 526 | for _, def := range (ast.MethodAndIfcDefs) { 527 | fmt.Fprintf (fout, indent2) 528 | conv (def).pp (fout, indent2) 529 | fmt.Fprintf (fout, "\n") 530 | } 531 | 532 | fmt.Fprintf (fout, indent) 533 | fmt.Fprintf (fout, "endinterface") 534 | } 535 | 536 | // AstInterfaceAssign is the parse of "interface ... = e" within a module 537 | func (ast *AstInterfaceAssign) pp (fout *os.File, indent string) () { 538 | fmt.Fprintf (fout, "interface ") 539 | if ast.Type != nil { 540 | conv (ast.Type).pp (fout, indent) 541 | fmt.Fprintf (fout, " ") 542 | } 543 | conv (ast.Name).pp (fout, indent) 544 | fmt.Fprintf (fout, " = ") 545 | conv (ast.Val).pp (fout, indent + " ") 546 | } 547 | 548 | // AstIf is the parse of: "if (E) S1 else S2" 549 | func (ast *AstIf) pp (fout *os.File, indent string) () { 550 | fmt.Fprintf (fout, "if (") 551 | conv (ast.ExprCond).pp (fout, indent) 552 | fmt.Fprintf (fout, ")\n") 553 | indent2 := indent + " " 554 | fmt.Fprintf (fout, indent2) 555 | conv (ast.StmtThen).pp (fout, indent2) 556 | if ast.StmtElse != nil { 557 | fmt.Fprintf (fout, "\n" + indent + "else\n" + indent2) 558 | conv (ast.StmtElse).pp (fout, indent2) 559 | } 560 | } 561 | 562 | // AstFor is the parse of: "for (type x = e; e; x = ...) stmt" 563 | func (ast *AstFor) pp (fout *os.File, indent string) () { 564 | fmt.Fprintf (fout, "for (") 565 | conv (ast.LoopInit).pp (fout, indent) 566 | fmt.Fprintf (fout, ";") 567 | conv (ast.LoopCond).pp (fout, indent) 568 | fmt.Fprintf (fout, ";") 569 | conv (ast.LoopIncr).pp (fout, indent) 570 | fmt.Fprintf (fout, ")\n") 571 | indent2 := indent + " " 572 | fmt.Fprintf (fout, indent2) 573 | conv (ast.LoopBody).pp (fout, indent2) 574 | } 575 | 576 | // AstWhile is the parse of: "while (e) stmt" 577 | func (ast *AstWhile) pp (fout *os.File, indent string) () { 578 | fmt.Fprintf (fout, "while (") 579 | conv (ast.LoopCond).pp (fout, indent) 580 | fmt.Fprintf (fout, ")\n") 581 | indent2 := indent + " " 582 | fmt.Fprintf (fout, indent2) 583 | conv (ast.LoopBody).pp (fout, indent2) 584 | } 585 | 586 | // AstInterfaceExpr is the parse of expression: interface ... endinterface 587 | func (ast *AstInterfaceExpr) pp (fout *os.File, indent string) () { 588 | fmt.Fprintf (fout, "interface ") 589 | if ast.Type != nil { 590 | conv (ast.Type).pp (fout, indent) 591 | } 592 | fmt.Fprintf (fout, ";\n") 593 | 594 | indent2 := indent + " " 595 | for _, def := range (ast.MethodAndIfcDefs) { 596 | fmt.Fprintf (fout, indent2) 597 | conv (def).pp (fout, indent2) 598 | fmt.Fprintf (fout, "\n") 599 | } 600 | 601 | fmt.Fprintf (fout, indent) 602 | fmt.Fprintf (fout, "endinterface") 603 | } 604 | 605 | // ================================================================ 606 | // StmtFSM 607 | 608 | // AstFSMseq is the parse of: 'seq stmt stmt ... endseq' 609 | func (ast *AstFSMseq) pp (fout *os.File, indent string) () { 610 | fmt.Fprintf (fout, "seq\n") 611 | indent2 := indent + " " 612 | for _, stmt := range (ast.Stmts) { 613 | fmt.Fprintf (fout, indent2) 614 | conv (stmt).pp (fout, indent2) 615 | fmt.Fprintf (fout, "\n") 616 | } 617 | fmt.Fprintf (fout, indent) 618 | fmt.Fprintf (fout, "endseq") 619 | } 620 | 621 | // AstFSMpar is the parse of: 'par stmt stmt ... endpar' 622 | func (ast *AstFSMpar) pp (fout *os.File, indent string) () { 623 | fmt.Fprintf (fout, "par\n") 624 | indent2 := indent + " " 625 | for _, stmt := range (ast.Stmts) { 626 | fmt.Fprintf (fout, indent2) 627 | conv (stmt).pp (fout, indent2) 628 | fmt.Fprintf (fout, "\n") 629 | } 630 | fmt.Fprintf (fout, indent) 631 | fmt.Fprintf (fout, "endpar") 632 | } 633 | 634 | // AstFSMif is the parse of: "if (E) S1 else S2" 635 | func (ast *AstFSMif) pp (fout *os.File, indent string) () { 636 | fmt.Fprintf (fout, "if (") 637 | conv (ast.ExprCond).pp (fout, indent) 638 | fmt.Fprintf (fout, ")\n") 639 | indent2 := indent + " " 640 | fmt.Fprintf (fout, indent2) 641 | conv (ast.StmtThen).pp (fout, indent2) 642 | if ast.StmtElse != nil { 643 | fmt.Fprintf (fout, "\n" + indent + "else\n" + indent2) 644 | conv (ast.StmtElse).pp (fout, indent2) 645 | } 646 | } 647 | 648 | // AstFSMfor is the parse of: 'for (init_stmts; cond; incr_stmts) fsmstmt' 649 | func (ast *AstFSMfor) pp (fout *os.File, indent string) () { 650 | fmt.Fprintf (fout, "for (") 651 | conv (ast.LoopInit).pp (fout, indent) 652 | fmt.Fprintf (fout, ";") 653 | conv (ast.LoopCond).pp (fout, indent) 654 | fmt.Fprintf (fout, ";") 655 | conv (ast.LoopIncr).pp (fout, indent) 656 | fmt.Fprintf (fout, ")\n") 657 | indent2 := indent + " " 658 | fmt.Fprintf (fout, indent2) 659 | conv (ast.LoopBody).pp (fout, indent2) 660 | } 661 | 662 | // AstFSMwhile is the parse of: "while (e) stmt" 663 | func (ast *AstFSMwhile) pp (fout *os.File, indent string) () { 664 | fmt.Fprintf (fout, "while (") 665 | conv (ast.LoopCond).pp (fout, indent) 666 | fmt.Fprintf (fout, ")\n") 667 | indent2 := indent + " " 668 | fmt.Fprintf (fout, indent2) 669 | conv (ast.LoopBody).pp (fout, indent2) 670 | } 671 | 672 | // AstFSMrepeat is the parse of: "repeat (n) stmt" 673 | func (ast *AstFSMrepeat) pp (fout *os.File, indent string) () { 674 | fmt.Fprintf (fout, "repeat (") 675 | conv (ast.LoopCount).pp (fout, indent) 676 | fmt.Fprintf (fout, ")\n") 677 | indent2 := indent + " " 678 | fmt.Fprintf (fout, indent2) 679 | conv (ast.LoopBody).pp (fout, indent2) 680 | } 681 | 682 | // AstFSMreturn is the parse of: 'return' 683 | func (ast *AstFSMreturn) pp (fout *os.File, indent string) () { 684 | fmt.Fprintf (fout, "return") 685 | } 686 | 687 | // AstFSMbreak is the parse of: 'break' 688 | func (ast *AstFSMbreak) pp (fout *os.File, indent string) () { 689 | fmt.Fprintf (fout, "break") 690 | } 691 | 692 | // AstFSMcontinue is the parse of: 'continue' 693 | func (ast *AstFSMcontinue) pp (fout *os.File, indent string) () { 694 | fmt.Fprintf (fout, "continue") 695 | } 696 | 697 | // ================================================================ 698 | // ASTs for patterns 699 | // Syntax of patterns: 700 | // Pattern variables 701 | // . * wildcard 702 | // . x pattern varIde 703 | // Pattern constants 704 | // 23 705 | // 2.5 706 | // "Hello" 707 | // Foo enum labels 708 | // Tagged unions 709 | // tagged tag pattern 710 | // Structs 711 | // tagged structname {member:pattern, ...} 712 | // Tuples 713 | // { pattern, ... } 714 | 715 | // AstPatternVarIde is the parse of a pattern .* or .x 716 | func (ast *AstPatternVarIde) pp (fout *os.File, indent string) () { 717 | fmt.Fprintf (fout, ".") 718 | conv (ast.varIde).pp (fout, indent) 719 | } 720 | 721 | // AstPatternConst is the parse of a pattern const integer, real, string, or Enum label 722 | func (ast *AstPatternConst) pp (fout *os.File, indent string) () { 723 | conv (ast.constant).pp (fout, indent) 724 | } 725 | 726 | // AstStructPattern is the parse of: tagged StructName { MemberName: Pattern, ..., } 727 | // and Tuple patterns (StructName is "Tuple", MemberNames are tuple_1, tuple_2, ... 728 | func (ast *AstStructPattern) pp (fout *os.File, indent string) () { 729 | fmt.Fprintf (fout, "struct ") 730 | conv (ast.StructName).pp (fout, indent) 731 | fmt.Fprintf (fout, " {") 732 | indent2 := indent + " " 733 | for j, memberName := range ast.MemberNames { 734 | conv (memberName).pp (fout, indent2) 735 | fmt.Fprintf (fout, ":") 736 | conv (ast.MemberPatterns [j]).pp (fout, indent2) 737 | if j < (len (ast.MemberNames) - 1) { 738 | fmt.Fprintf (fout, ",") 739 | } else { 740 | fmt.Fprintf (fout, "}") 741 | } 742 | } 743 | } 744 | 745 | // AstTaggedUnionPattern is the parse of: tagged UnionName [ Pattern ] 746 | func (ast *AstTaggedUnionPattern) pp (fout *os.File, indent string) () { 747 | fmt.Fprintf (fout, "tagged union ") 748 | indent2 := indent + " " 749 | conv (ast.TaggedUnionName).pp (fout, indent2) 750 | if ast.MemberPattern != nil { 751 | fmt.Fprintf (fout, " (") 752 | conv (ast.MemberPattern).pp (fout, indent2) 753 | fmt.Fprintf (fout, ")") 754 | } 755 | } 756 | 757 | // ================================================================ 758 | // Top-level constructs in a package 759 | 760 | // AstPackage is parse of 'package pkgStmt ... pkgStmt endpackage' 761 | func (ast *AstPackage) pp (fout *os.File, indent string) { 762 | if ast.PackageName != nil { 763 | fmt.Fprintf (fout, "package ") 764 | conv (ast.PackageName).pp (fout, indent) 765 | fmt.Fprintf (fout, ";\n") 766 | } 767 | 768 | indent2 := indent + " " 769 | for _, decl := range ast.PackageStmts { 770 | fmt.Fprintf (fout, indent2) 771 | conv (decl).pp (fout, indent2) 772 | fmt.Fprintf (fout, "\n\n") 773 | } 774 | 775 | if ast.PackageName != nil { 776 | fmt.Fprintf (fout, indent) 777 | fmt.Fprintf (fout, "endpackage: ") 778 | conv (ast.PackageName).pp (fout, indent) 779 | fmt.Fprintf (fout, "\n") 780 | } 781 | } 782 | 783 | // AstImport is parse of 'import x :: *;' 784 | func (ast *AstImport) pp (fout *os.File, indent string) { 785 | fmt.Fprintf (fout, "import ") 786 | conv (ast.PackageName).pp (fout, indent) 787 | fmt.Fprintf (fout, " :: *;") 788 | } 789 | 790 | // AstExport is parse of 'export x, y, z (..), w, ...;' 791 | func (ast *AstExport) pp (fout *os.File, indent string) { 792 | fmt.Fprintf (fout, "export ") 793 | indent2 := indent + " " 794 | for j, ide := range (ast.Ides) { 795 | conv (ide).pp (fout, indent2) 796 | if ast.WithMembers [j] { fmt.Fprintf (fout, " (..)") } 797 | if j == (len (ast.Ides) - 1) { 798 | fmt.Fprintf (fout, ";") 799 | } else { 800 | fmt.Fprintf (fout, ",\n") 801 | fmt.Fprintf (fout, indent2) 802 | } 803 | } 804 | } 805 | 806 | // AstImportBDPI is parse of 'import "BDPI" function_proto' 807 | func (ast *AstImportBDPI) pp (fout *os.File, indent string) { 808 | fmt.Fprintf (fout, "import \"BDPI\"\n") 809 | 810 | // TODO: ImportBDPI does not yet handle renaming of the imported function 811 | 812 | indent2 := indent + " " 813 | fmt.Fprintf (fout, indent2) 814 | ast.Proto.pp (fout, indent2) 815 | fmt.Fprintf (fout, ";") 816 | } 817 | 818 | // AstTypedef is the parse of a BSV statement: "typedef typeDefinedAs newtype deriving (typeclass, ...);" 819 | func (ast *AstTypedef) pp (fout *os.File, indent string) () { 820 | fmt.Fprintf (fout, "typedef ") 821 | indent2 := indent + " " 822 | conv (ast.TypedefDefinedAs).pp (fout, indent2) 823 | fmt.Fprintf (fout, " ") 824 | conv (ast.TypedefDefinee).pp (fout, indent2) 825 | if len (ast.TypeclassIdes) > 0 { 826 | fmt.Fprintf (fout, "\n" + indent + "deriving ") 827 | for j, deriveType := range (ast.TypeclassIdes) { 828 | if j == 0 { 829 | fmt.Fprintf (fout, "(") 830 | } else { 831 | fmt.Fprintf (fout, ", ") 832 | } 833 | conv (deriveType).pp (fout, indent2) 834 | } 835 | fmt.Fprintf (fout, ")"); 836 | } 837 | fmt.Fprintf (fout, ";") 838 | } 839 | 840 | // AstIfcDecl is the parse of a top-level BSV declaration: 'interface ... endinterface' 841 | func (ast *AstIfcDecl) pp (fout *os.File, indent string) { 842 | fmt.Fprintf (fout, "interface ") 843 | conv (ast.Ifc).pp (fout, indent) 844 | fmt.Fprintf (fout, ";\n") 845 | indent2 := indent + " " 846 | for _, subIfcOrMethodDecl := range (ast.SubIfcOrMethodDecls) { 847 | fmt.Fprintf (fout, indent2) 848 | conv (subIfcOrMethodDecl).pp (fout, indent2) 849 | fmt.Fprintf (fout, ";\n") 850 | } 851 | fmt.Fprintf (fout, indent) 852 | fmt.Fprintf (fout, "endinterface") 853 | } 854 | 855 | // Sub-interface within an interface declaration 856 | func (ast *AstIfcDeclSubIfcDecl) pp (fout *os.File, indent string) { 857 | fmt.Fprintf (fout, "interface ") 858 | conv (ast.SubIfcType).pp (fout, indent) 859 | fmt.Fprintf (fout, " ") 860 | conv (ast.SubIfcName).pp (fout, indent) 861 | } 862 | 863 | // Method declaration within an interface declaration 864 | func (ast *AstIfcDeclMethodDecl) pp (fout *os.File, indent string) { 865 | fmt.Fprintf (fout, "method ") 866 | conv (ast.ReturnType).pp (fout, indent) 867 | fmt.Fprintf (fout, " ") 868 | conv (ast.MethodName).pp (fout, indent) 869 | if len (ast.ArgNames) != 0 { 870 | fmt.Fprintf (fout, " (") 871 | for j, argName := range (ast.ArgNames) { 872 | argType := ast.ArgTypes [j] 873 | conv (argType).pp (fout, indent) 874 | fmt.Fprintf (fout, " ") 875 | conv (argName).pp (fout, indent) 876 | if (j < len (ast.ArgNames) - 1) { 877 | fmt.Fprintf (fout, ",") 878 | } 879 | } 880 | fmt.Fprintf (fout, ")") 881 | } 882 | } 883 | 884 | // instance typeclassIde # ( type { , type } ) [ provisos ] ; 885 | // { varAssign ; | functionDef | moduleDef } 886 | // endinstance [ : typeclassIde ] 887 | func (ast *AstInstance) pp (fout *os.File, indent string) { 888 | fmt.Fprintf (fout, "instance ") 889 | conv (ast.TypeclassIde).pp (fout, indent) 890 | fmt.Fprintf (fout, " #(") 891 | for j, ty := range (ast.Types) { 892 | if j != 0 { fmt.Fprintf (fout, ", ") } 893 | conv (ty).pp (fout, indent) 894 | } 895 | fmt.Fprintf (fout, ")") 896 | 897 | if len (ast.Provisos) == 0 { 898 | fmt.Fprintf (fout, ";\n") 899 | } else { 900 | fmt.Fprintf (fout, "\n") 901 | fmt.Fprintf (fout, indent + " provisos (") 902 | indent2 := indent + " " 903 | for j, proviso := range (ast.Provisos) { 904 | conv (proviso).pp (fout, indent2) 905 | if j == (len (ast.Provisos) - 1) { 906 | fmt.Fprintf (fout, ");\n") 907 | } else { 908 | fmt.Fprintf (fout, ",\n") 909 | fmt.Fprintf (fout, indent2) 910 | } 911 | } 912 | } 913 | 914 | indent3 := indent + " " 915 | for _, stmt := range ast.Stmts { 916 | fmt.Fprintf (fout, indent3) 917 | conv (stmt).pp (fout, indent3) 918 | fmt.Fprintf (fout, "\n") 919 | } 920 | 921 | fmt.Fprintf (fout, indent) 922 | fmt.Fprintf (fout, "endinstance") 923 | } 924 | 925 | // ================================================================ 926 | --------------------------------------------------------------------------------