OpenQASM 3.0 Go Parser
May 19, 2026 · View on GitHub
A Go parser for OpenQASM 3.0, generated from the official ANTLR grammar.
Overview
This project provides a Go implementation of the OpenQASM 3.0 parser, based on the official ANTLR grammar from the OpenQASM specification. It allows you to parse OpenQASM 3.0 programs in Go applications.
Features
- Full OpenQASM 3.0 grammar support
- Generated from official ANTLR grammar files
- Easy-to-use API for parsing strings, files, and readers
- Visitor pattern support for traversing parse trees
- Comprehensive error reporting
Installation
This is a library module. Add it to your Go project:
# In your Go project directory
go get github.com/jwoehr/gopenqasm3
Or import it directly in your code and run go mod tidy:
import "github.com/jwoehr/gopenqasm3/src/parser"
Installing Example Programs
If you want to install the example programs as command-line tools:
go install github.com/jwoehr/gopenqasm3/examples/simple_parse@latest
go install github.com/jwoehr/gopenqasm3/examples/detailed_parse@latest
These will be installed to your $GOPATH/bin directory.
Requirements
- Go 1.16 or later
- ANTLR 4.9.2 (for regenerating parser from grammar)
Usage
Basic Parsing
package main
import (
"fmt"
"github.com/Qiskit/gopenqasm3/src/parser"
)
func main() {
qasm := `OPENQASM 3.0;
include "stdgates.inc";
qubit[2] q;
bit[2] c;
h q[0];
cx q[0], q[1];
c = measure q;
`
// Parse the program
result := parser.ParseString(qasm)
// Check for errors
if result.HasErrors() {
fmt.Println("Parsing errors:")
fmt.Println(result.GetErrorString())
return
}
fmt.Println("Parsing successful!")
}
Parsing from a File
result, err := parser.ParseFile("program.qasm")
if err != nil {
log.Fatal(err)
}
if result.HasErrors() {
fmt.Println("Parsing errors:", result.GetErrorString())
}
Traversing the Parse Tree
There are two main approaches to traverse the parse tree:
1. Direct Tree Walking (Recommended for Complex Analysis)
result := parser.ParseString(qasm)
if !result.HasErrors() {
// Walk the tree directly
program := result.Program
// Access version
if program.Version() != nil {
version := program.Version().VersionSpecifier().GetText()
}
// Iterate through statements
for _, stmt := range program.AllStatementOrScope() {
// Check statement type and process
if stmt.Statement() != nil {
statement := stmt.Statement()
if statement.QuantumDeclarationStatement() != nil {
// Handle qubit declaration
qubitDecl := statement.QuantumDeclarationStatement()
name := qubitDecl.Identifier().GetText()
}
}
}
}
2. Using the Visitor Pattern
// Create a custom visitor
type MyVisitor struct {
*parser.Baseqasm3ParserVisitor
}
func (v *MyVisitor) VisitQuantumDeclarationStatement(ctx *parser.QuantumDeclarationStatementContext) interface{} {
fmt.Println("Found qubit:", ctx.Identifier().GetText())
return v.VisitChildren(ctx)
}
// Use the visitor
visitor := &MyVisitor{Baseqasm3ParserVisitor: &parser.Baseqasm3ParserVisitor{}}
result := parser.ParseString(qasm)
if !result.HasErrors() {
result.Program.Accept(visitor)
}
Note: The detailed_parse.go example demonstrates the direct tree walking approach, which provides more explicit control over traversal.
Project Structure
.
├── src/
│ └── parser/ # Generated parser and utilities
│ ├── qasm3_lexer.go
│ ├── qasm3_parser.go
│ ├── qasm3parser_visitor.go
│ ├── qasm3parser_base_visitor.go
│ ├── parser.go # High-level parsing API
│ └── visitor_example.go
├── examples/
│ └── simple_parse.go # Example usage
├── go.mod
└── README.md
Regenerating the Parser
If you need to regenerate the parser from the ANTLR grammar files:
# Install ANTLR 4.9.2
# Download grammar files from https://github.com/Qiskit/openqasm
# Generate Go code
antlr4 -Dlanguage=Go -o src/parser -visitor \
/path/to/qasm3Lexer.g4 \
/path/to/qasm3Parser.g4
API Reference
ParseResult
type ParseResult struct {
Program *ProgramContext // The parsed program tree
Errors []string // List of parsing errors
}
func (pr *ParseResult) HasErrors() bool
func (pr *ParseResult) GetErrorString() string
Parsing Functions
// Parse from string
func ParseString(input string) *ParseResult
// Parse from file
func ParseFile(filename string) (*ParseResult, error)
// Parse from io.Reader
func ParseReader(reader io.Reader) (*ParseResult, error)
Examples
See the examples/ directory for complete working examples:
simple_parse.go- Basic parsing example showing success/failuredetailed_parse.go- Comprehensive parse tree visualization
Running the Examples
# Build the examples
go build -o bin/simple_parse examples/simple_parse.go
go build -o bin/detailed_parse examples/detailed_parse.go
# Run them
./bin/simple_parse
./bin/detailed_parse
# Or run directly
go run examples/simple_parse.go
go run examples/detailed_parse.go
Detailed Parse Example Output
The detailed_parse example shows a complete parse tree structure:
Program
├─ Version: 3.0
├─ Include: "stdgates.inc"
├─ Qubit Declaration: qubit[3] q
├─ Classical Declaration: bit[3] c
├─ Gate Definition: my_gate(param) a,b
├─ Body
├─ Gate Call: rx(param) a
├─ Gate Call: cx a,b
├─ Gate Call: h q[0]
├─ If Statement: condition: c[0]==1
├─ Then
├─ Gate Call: x q[0]
├─ Else
├─ Gate Call: y q[0]
├─ For Loop: int i in 0:2
├─ Body
├─ Gate Call: h q[i]
├─ Measurement: measureq[0] -> c[0]
This demonstrates how the parser correctly identifies and structures all OpenQASM 3.0 language constructs.
OpenQASM 3.0 Language Support
This parser supports the full OpenQASM 3.0 specification, including:
- Quantum declarations (qubits, quantum registers)
- Classical declarations (bits, integers, floats, angles, etc.)
- Gate definitions and applications
- Measurements
- Control flow (if/else, for, while, switch)
- Subroutines and extern functions
- Calibration blocks (cal, defcal)
- Pulse-level control
- Arrays and complex types
- Annotations and pragmas
Contributing
Contributions are welcome! Please ensure that:
- Code follows Go conventions
- Tests pass
- Documentation is updated
License
This project follows the same license as the OpenQASM specification.
References
Acknowledgments
This parser is generated from the official OpenQASM 3.0 ANTLR grammar maintained by the Qiskit team.