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:

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/failure
  • detailed_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:

  1. Code follows Go conventions
  2. Tests pass
  3. 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.