refactor parser

This commit is contained in:
Andrew W. Cross 2017-03-15 16:37:28 -04:00
parent 0581d8e719
commit 739e4c1416
309 changed files with 2067 additions and 1717 deletions

View File

@ -1,58 +0,0 @@
#!/usr/bin/env python
# Author: Jim Challenger
import os
import sys
from . import _qasm_yy as qasm
import traceback
class Qasm(object):
def __init__(self, filename = None, data = None):
if ( filename == None and data == None ):
raise qasm.QasmException("Missing input file and/or data")
if ( filename != None and data != None ):
raise qasm.QasmException("File and data must not both be specified initializing qasm")
self._filename = filename
self._data = data
def print_tokens(self):
if ( self._filename ):
self._data = open(self._filename).read()
qasm_p = qasm.QasmParser(self._filename)
return qasm_p.print_tokens()
def parse(self):
if ( self._filename ):
self._data = open(self._filename).read()
qasm_p = qasm.QasmParser(self._filename)
qasm_p.parse_debug(False)
return qasm_p.parse(self._data)
def main(args):
try:
q = Qasm(filename=args[0])
ast = q.parse()
print('---------------------------------------- PARSE TREE ----------------------------------------')
ast.to_string(0)
print('-------------------------------------- END PARSE TREE --------------------------------------')
except qasm.QasmException as e:
print('--------------------------------------------------------------------------------')
print(e.msg)
print('--------------------------------------------------------------------------------')
except Exception as e:
print('--------------------------------------------------------------------------------')
print(sys.exc_info()[0], 'Exception parsing qasm file')
traceback.print_exc()
print('--------------------------------------------------------------------------------')
if __name__ == '__main__':
main(sys.argv[1:])

View File

@ -1,2 +0,0 @@
from ._Qasm import Qasm
from . import _qasm_yy as qasm

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
from ._qasm import Qasm

View File

@ -0,0 +1,24 @@
from ._barrier import Barrier
from ._binaryop import BinaryOp
from ._cnot import Cnot
from ._creg import Creg
from ._customunitary import CustomUnitary
from ._expressionlist import ExpressionList
from ._external import External
from ._gate import Gate
from ._gatebody import GateBody
from ._id import Id
from ._idlist import IdList
from ._if import If
from ._indexedid import IndexedId
from ._intnode import Int
from ._magic import Magic
from ._measure import Measure
from ._opaque import Opaque
from ._prefix import Prefix
from ._primarylist import PrimaryList
from ._program import Program
from ._qreg import Qreg
from ._real import Real
from ._reset import Reset
from ._universalunitary import UniversalUnitary

View File

@ -0,0 +1,21 @@
"""
Node for an OPENQASM barrier statement.
Author: Jim Challenger
"""
from ._node import Node
class Barrier(Node):
"""Node for an OPENQASM barrier statement.
children[0] is a primarylist node.
"""
def __init__(self, children):
"""Create the barrier node."""
Node.__init__(self, 'barrier', children, None)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return "barrier " + self.children[0].qasm() + ";"

View File

@ -0,0 +1,24 @@
"""
Node for an OPENQASM binary operation expression.
Author: Jim Challenger
"""
from ._node import Node
class BinaryOp(Node):
"""Node for an OPENQASM binary operation exprssion.
children[0] is the operation, as a character.
children[1] is the left expression.
children[2] is the right expression.
"""
def __init__(self, children):
"""Create the binaryop node."""
Node.__init__(self, 'binop', children, None)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return "(" + self.children[1].qasm() + self.children[0] + \
self.children[2].qasm() + ")"

View File

@ -0,0 +1,23 @@
"""
Node for an OPENQASM CNOT statement.
Author: Jim Challenger
"""
from ._node import Node
class Cnot(Node):
"""Node for an OPENQASM CNOT statement.
children[0], children[1] are id nodes if CX is inside a gate body,
otherwise they are primary nodes.
"""
def __init__(self, children):
"""Create the cnot node."""
Node.__init__(self, 'cnot', children, None)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return "CX " + self.children[0].qasm() + "," + \
self.children[1].qasm() + ";"

View File

@ -0,0 +1,37 @@
"""
Node for an OPENQASM creg statement.
Author: Jim Challenger
"""
from ._node import Node
class Creg(Node):
"""Node for an OPENQASM creg statement.
children[0] is an indexedid node.
"""
def __init__(self, children):
"""Create the creg node."""
Node.__init__(self, 'creg', children, None)
# This is the indexed id, the full "id[n]" object
self.id = children[0]
# Name of the creg
self.name = self.id.name
# Source line number
self.line = self.id.line
# Source file name
self.file = self.id.file
# Size of the register
self.index = self.id.index
def to_string(self, indent):
"""Print the node data, with indent."""
ind = indent * ' '
print(ind, 'creg')
self.children[0].to_string(indent + 3)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return "creg " + self.id.qasm() + ";"

View File

@ -0,0 +1,41 @@
"""
Node for an OPENQASM custom gate statement.
Author: Jim Challenger
"""
from ._node import Node
class CustomUnitary(Node):
"""Node for an OPENQASM custom gate statement.
children[0] is an id node.
children[1] is an exp_list (if len==3) or primary_list.
children[2], if present, is a primary_list.
Has properties:
.id = id node
.name = gate name string
.arguments = None or exp_list node
.bitlist = primary_list node
"""
def __init__(self, children):
"""Create the custom gate node."""
Node.__init__(self, 'custom_unitary', children, None)
self.id = children[0]
self.name = self.id.name
if len(children) == 3:
self.arguments = children[1]
self.bitlist = children[2]
else:
self.arguments = None
self.bitlist = children[1]
def qasm(self):
"""Return the corresponding OPENQASM string."""
s = self.name
if self.arguments is not None:
s += "(" + self.arguments.qasm() + ")"
s += " " + self.bitlist.qasm() + ";"
return s

View File

@ -0,0 +1,25 @@
"""
Node for an OPENQASM expression list.
Author: Jim Challenger
"""
from ._node import Node
class ExpressionList(Node):
"""Node for an OPENQASM expression list.
children are expression nodes.
"""
def __init__(self, children):
"""Create the expression list node."""
Node.__init__(self, 'expression_list', children, None)
def size(self):
"""Return the number of expressions."""
return len(self.children)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return ",".join([self.children[j].qasm() for j in range(self.size())])

View File

@ -0,0 +1,18 @@
"""
Node for an OPENQASM external function.
Author: Jim Challenger
"""
from ._node import Node
class External(Node):
"""Node for an OPENQASM external function.
children[0] is an id node with the name of the function.
children[1] is an expression node.
"""
def __init__(self, children):
"""Create the external node."""
Node.__init__(self, 'external', children, None)

View File

@ -0,0 +1,54 @@
"""
Node for an OPENQASM gate definition.
Author: Jim Challenger
"""
from ._node import Node
class Gate(Node):
"""Node for an OPENQASM gate definition.
children[0] is an id node.
If len(children) is 3, children[1] is an idlist node,
and children[2] is a gatebody node.
Otherwise, children[1] is an expressionlist node,
children[2] is an idlist node, and children[3] is a gatebody node.
"""
def __init__(self, children):
"""Create the gate node."""
Node.__init__(self, 'gate', children, None)
self.id = children[0]
# The next three fields are required by the symbtab
self.name = self.id.name
self.line = self.id.line
self.file = self.id.file
if len(children) == 3:
self.arguments = None
self.bitlist = children[1]
self.body = children[2]
else:
self.arguments = children[1]
self.bitlist = children[2]
self.body = children[3]
def n_args(self):
"""Return the number of parameter expressions."""
if self.arguments:
return self.arguments.size()
return 0
def n_bits(self):
"""Return the number of qubit arguments."""
return self.bitlist.size()
def qasm(self):
"""Return the corresponding OPENQASM string."""
s = "gate " + self.name
if self.arguments is not None:
s += "(" + self.arguments.qasm() + ")"
s += " " + self.bitlist.qasm() + "\n"
s += "{\n" + self.body.qasm() + "}"
return s

View File

@ -0,0 +1,33 @@
"""
Node for an OPENQASM custom gate body.
Author: Jim Challenger
"""
from ._node import Node
class GateBody(Node):
"""Node for an OPENQASM custom gate body.
children is a list of gate operation nodes.
These are one of barrier, custom_unitary, U, or CX.
"""
def __init__(self, children):
"""Create the gatebody node."""
Node.__init__(self, 'gate_body', children, None)
def qasm(self):
"""Return the corresponding OPENQASM string."""
s = ""
for c in self.children:
s += " " + c.qasm() + "\n"
return s
def calls(self):
"""Return a list of custom gate names in this gate body."""
lst = []
for c in self.children:
if c.type == "custom_unitary":
lst.append(c.name)
return lst

View File

@ -0,0 +1,33 @@
"""
Node for an OPENQASM id.
Author: Jim Challenger
"""
from ._node import Node
class Id(Node):
"""Node for an OPENQASM id.
The node has no children but has fields name, line, and file.
There is a flag is_bit that is set when XXXXX to help with scoping.
"""
def __init__(self, id, line, file):
"""Create the id node."""
Node.__init__(self, "id", None, None)
self.name = id
self.line = line
self.file = file
# To help with scoping rules, so we know the id is a bit,
# this flag is set to True when the id appears in a gate declaration
self.is_bit = False
def to_string(self, indent):
"""Print the node with indent."""
ind = indent * ' '
print(ind, 'id', self.name)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return self.name

View File

@ -0,0 +1,25 @@
"""
Node for an OPENQASM idlist.
Author: Jim Challenger
"""
from ._node import Node
class IdList(Node):
"""Node for an OPENQASM idlist.
children is a list of id nodes.
"""
def __init__(self, children):
"""Create the idlist node."""
Node.__init__(self, 'id_list', children, None)
def size(self):
"""Return the length of the list."""
return len(self.children)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return ",".join([self.children[j].qasm() for j in range(self.size())])

View File

@ -0,0 +1,25 @@
"""
Node for an OPENQASM if statement.
Author: Jim Challenger
"""
from ._node import Node
class If(Node):
"""Node for an OPENQASM if statement.
children[0] is an id node.
children[1] is an integer node.
children[2] is quantum operation node, including U, CX, custom_unitary,
measure, reset, (and BUG: barrier, if).
"""
def __init__(self, children):
"""Create the if node."""
Node.__init__(self, 'if', children, None)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return "if(" + self.children[0].qasm() + "==" \
+ self.children[1].qasm() + ") " + self.children[2].qasm()

View File

@ -0,0 +1,32 @@
"""
Node for an OPENQASM indexed id.
Author: Jim Challenger
"""
from ._node import Node
class IndexedId(Node):
"""Node for an OPENQASM indexed id.
children[0] is an id node.
children[1] is an integer (not a node).
"""
def __init__(self, children):
"""Create the indexed id node."""
Node.__init__(self, 'indexed_id', children, None)
self.id = children[0]
self.name = self.id.name
self.line = self.id.line
self.file = self.id.file
self.index = children[1]
def to_string(self, indent):
"""Print with indent."""
ind = indent * ' '
print(ind, 'indexed_id', self.name, self.index)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return self.name + "[%d]" % self.index

View File

@ -0,0 +1,27 @@
"""
Node for an OPENQASM integer.
Author: Jim Challenger
"""
from ._node import Node
class Int(Node):
"""Node for an OPENQASM integer.
This node has no children. The data is in the value field.
"""
def __init__(self, id):
"""Create the integer node."""
Node.__init__(self, "int", None, None)
self.value = id
def to_string(self, indent):
"""Print with indent."""
ind = indent * ' '
print(ind, 'int', self.value)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return "%d" % self.value

View File

@ -0,0 +1,21 @@
"""
Node for an OPENQASM file identifier/version statement.
Author: Jim Challenger
"""
from ._node import Node
class Magic(Node):
"""Node for an OPENQASM file identifier/version statement ("magic number").
children[0] is a floating point number (not a node).
"""
def __init__(self, children):
"""Create the version node."""
Node.__init__(self, 'magic', children, None)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return "OPENQASM %.1f;" % self.children[0]

View File

@ -0,0 +1,23 @@
"""
Node for an OPENQASM measure statement.
Author: Jim Challenger
"""
from ._node import Node
class Measure(Node):
"""Node for an OPENQASM measure statement.
children[0] is a primary node (id or indexedid)
children[1] is a primary node (id or indexedid)
"""
def __init__(self, children):
"""Create the measure node."""
Node.__init__(self, 'measure', children, None)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return "measure " + self.children[0].qasm() + " -> " + \
self.children[1].qasm() + ";"

View File

@ -0,0 +1,50 @@
"""
Base node object for the OPENQASM syntax tree.
Author: Jim Challenger
"""
class Node(object):
"""Base node object for the OPENQASM syntax tree."""
def __init__(self, type, children=None, root=None):
"""Construct a new node object."""
self.type = type
if children:
self.children = children
else:
self.children = []
self.root = root
# True if this node is an expression node, False otherwise
self.expression = False
def is_expression(self):
"""Return True if this is an expression node."""
return self.expression
def add_child(self, n):
"""Add a child node."""
self.children.append(n)
def to_string(self, indent):
"""Print with indent."""
ind = indent * ' '
if self.root:
print(ind, self.type, '---', self.root)
else:
print(ind, self.type)
indent = indent + 3
ind = indent * ' '
for c in self.children:
if c is None:
print("OOPS! type of parent is", type(self))
print(self.children)
if type(c) is str:
print(ind, c)
elif type(c) is int:
print(ind, str(c))
elif type(c) is float:
print(ind, str(c))
else:
c.to_string(indent)

View File

@ -0,0 +1,49 @@
"""
Node for an OPENQASM opaque gate declaration.
Author: Jim Challenger
"""
from ._node import Node
class Opaque(Node):
"""Node for an OPENQASM opaque gate declaration.
children[0] is an id node.
If len(children) is 3, children[1] is an expressionlist node,
and children[2] is an idlist node.
Otherwise, children[1] is an idlist node.
"""
def __init__(self, children):
"""Create the opaque gate node."""
Node.__init__(self, 'opaque', children, None)
self.id = children[0]
# The next three fields are required by the symbtab
self.name = self.id.name
self.line = self.id.line
self.file = self.id.file
if len(children) == 3:
self.arguments = children[1]
self.bitlist = children[2]
else:
self.arguments = None
self.bitlist = children[1]
def n_args(self):
"""Return the number of parameter expressions."""
if self.arguments:
return self.arguments.size()
return 0
def n_bits(self):
"""Return the number of qubit arguments."""
return self.bitlist.size()
def qasm(self):
"""Return the corresponding OPENQASM string."""
s = "opaque %s" % self.name
if self.arguments is not None:
s += "(" + self.arguments.qasm() + ")"
s += self.bitlist.qasm() + ";"
return s

View File

@ -0,0 +1,22 @@
"""
Node for an OPENQASM prefix expression.
Author: Jim Challenger
"""
from ._node import Node
class Prefix(Node):
"""Node for an OPENQASM prefix expression.
children[0] is a prefix string such as '-'.
children[1] is an expression node.
"""
def __init__(self, children):
"""Create the prefix node."""
Node.__init__(self, 'prefix', children, None)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return self.children[0] + "(" + self.children[1].qasm() + ")"

View File

@ -0,0 +1,25 @@
"""
Node for an OPENQASM primarylist.
Author: Jim Challenger
"""
from ._node import Node
class PrimaryList(Node):
"""Node for an OPENQASM primarylist.
children is a list of primary nodes. Primary nodes are indexedid or id.
"""
def __init__(self, children):
"""Create the primarylist node."""
Node.__init__(self, 'primary_list', children, None)
def size(self):
"""Return the size of the list."""
return len(self.children)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return ",".join([self.children[j].qasm() for j in range(self.size())])

View File

@ -0,0 +1,24 @@
"""
Node for an OPENQASM program.
Author: Jim Challenger
"""
from ._node import Node
class Program(Node):
"""Node for an OPENQASM program.
children is a list of nodes (statements).
"""
def __init__(self, children):
"""Create the program node."""
Node.__init__(self, 'program', children, None)
def qasm(self):
"""Return the corresponding OPENQASM string."""
s = ""
for c in self.children:
s += c.qasm() + "\n"
return s

View File

@ -0,0 +1,37 @@
"""
Node for an OPENQASM qreg statement.
Author: Jim Challenger
"""
from ._node import Node
class Qreg(Node):
"""Node for an OPENQASM qreg statement.
children[0] is an indexedid node.
"""
def __init__(self, children):
"""Create the qreg node."""
Node.__init__(self, 'qreg', children, None)
# This is the indexed id, the full "id[n]" object
self.id = children[0]
# Name of the qreg
self.name = self.id.name
# Source line number
self.line = self.id.line
# Source file name
self.file = self.id.file
# Size of the register
self.index = self.id.index
def to_string(self, indent):
"""Print the node data, with indent."""
ind = indent * ' '
print(ind, 'qreg')
self.children[0].to_string(indent + 3)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return "qreg " + self.id.qasm() + ";"

View File

@ -0,0 +1,27 @@
"""
Node for an OPENQASM real number.
Author: Jim Challenger
"""
from ._node import Node
class Real(Node):
"""Node for an OPENQASM real number.
This node has no children. The data is in the value field.
"""
def __init__(self, id):
"""Create the real node."""
Node.__init__(self, "real", None, None)
self.value = id
def to_string(self, indent):
"""Print with indent."""
ind = indent * ' '
print(ind, 'real', self.value)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return "%0.15f" % self.value # TODO: control the precision

View File

@ -0,0 +1,21 @@
"""
Node for an OPENQASM reset statement.
Author: Jim Challenger
"""
from ._node import Node
class Reset(Node):
"""Node for an OPENQASM reset statement.
children[0] is a primary node (id or indexedid)
"""
def __init__(self, children):
"""Create the reset node."""
Node.__init__(self, 'reset', children, None)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return "reset " + self.children[0].qasm() + ";"

View File

@ -0,0 +1,23 @@
"""
Node for an OPENQASM U statement.
Author: Jim Challenger
"""
from ._node import Node
class UniversalUnitary(Node):
"""Node for an OPENQASM U statement.
children[0] is an expressionlist node.
children[1] is a primary node (id or indexedid).
"""
def __init__(self, children):
"""Create the U node."""
Node.__init__(self, 'universal_unitary', children, None)
def qasm(self):
"""Return the corresponding OPENQASM string."""
return "U(" + self.children[0].qasm() + ") " + \
self.children[1].qasm() + ";"

37
qiskit_sdk/qasm/_qasm.py Normal file
View File

@ -0,0 +1,37 @@
"""
OPENQASM circuit object.
Author: Jim Challenger
"""
from ._qasmexception import QasmException
from ._qasmparser import QasmParser
class Qasm(object):
"""OPENQASM circuit object."""
def __init__(self, filename=None, data=None):
"""Create an OPENQASM circuit object."""
if filename is None and data is None:
raise QasmException("Missing input file and/or data")
if filename is not None and data is not None:
raise QasmException("File and data must not both be"
+ " specified initializing qasm")
self._filename = filename
self._data = data
def print_tokens(self):
"""Parse and print tokens."""
if self._filename:
self._data = open(self._filename).read()
qasm_p = QasmParser(self._filename)
return qasm_p.print_tokens()
def parse(self):
"""Parse the data."""
if self._filename:
self._data = open(self._filename).read()
qasm_p = QasmParser(self._filename)
qasm_p.parse_debug(False)
return qasm_p.parse(self._data)

View File

@ -0,0 +1,17 @@
"""
Exception for errors raised while parsing OPENQASM.
Author: Jim Challenger
"""
class QasmException(Exception):
"""Base class for errors raised while parsing OPENQASM."""
def __init__(self, *msg):
"""Set the error message."""
self.msg = ' '.join(msg)
def __str__(self):
"""Return the message."""
return repr(self.msg)

View File

@ -0,0 +1,213 @@
"""
OPENQASM Lexer.
This is a wrapper around the PLY lexer to support the "include" statement
by creating a stack of lexers.
Author: Jim Challenger
"""
import os
import ply.lex as lex
from ._qasmexception import QasmException
from . import _node as Node
class QasmLexer(object):
"""OPENQASM Lexer.
This is a wrapper around the PLY lexer to support the "include" statement
by creating a stack of lexers.
"""
def __mklexer__(self, filename):
"""Create a PLY lexer."""
self.lexer = lex.lex(module=self, debug=False)
self.filename = filename
self.lineno = 1
def __init__(self, filename):
"""Create the OPENQASM lexer."""
self.__mklexer__(filename)
self.stack = []
def input(self, data):
"""Set the input text data."""
self.data = data
self.lexer.input(data)
def token(self):
"""Return the next token."""
ret = self.lexer.token()
return ret
def pop(self):
"""Pop a PLY lexer off the stack."""
self.lexer = self.stack.pop()
self.filename = self.lexer.qasm_file
self.lineno = self.lexer.qasm_line
def push(self, filename):
"""Push a PLY lexer on the stack to parse filename."""
self.lexer.qasm_file = self.filename
self.lexer.qasm_line = self.lineno
self.stack.append(self.lexer)
self.__mklexer__(filename)
self.data = open(filename).read()
self.lexer.input(self.data)
# ---- Beginning of the PLY lexer ----
literals = r'=()[]{};<>,.+-/*"'
tokens = (
'NNINTEGER',
'BARRIER',
'OPAQUE',
'RESET',
'IF',
'REAL',
'QREG',
'CREG',
'GATE',
'PI',
'CX',
'U',
'MEASURE',
'MAGIC',
'ASSIGN',
'MATCHES',
'ID',
'STRING',
)
def t_REAL(self, t):
r'(([0-9]+|([0-9]+)?\.[0-9]+|[0-9]+\.)[eE][+-]?[0-9]+)|(([0-9]+)?\.[0-9]+|[0-9]+\.)'
t.value = float(t.value)
# tad nasty, see mkfloat.py to see how this is derived from python spec
return t
def t_NNINTEGER(self, t):
r'\d+'
t.value = int(t.value)
return t
def t_QREG(self, t):
'qreg'
return t
def t_CREG(self, t):
'creg'
return t
def t_GATE(self, t):
'gate'
return t
def t_MEASURE(self, t):
'measure'
return t
def t_IF(self, t):
'if'
return t
def t_RESET(self, t):
'reset'
return t
def t_ASSIGN(self, t):
'->'
return t
def t_MATCHES(self, t):
'=='
return t
def t_BARRIER(self, t):
'barrier'
return t
def t_OPAQUE(self, t):
'opaque'
return t
def t_STRING(self, t):
r'\"([^\\\"]|\\.)*\"'
return t
def t_INCLUDE(self, t):
'include'
'''
Now eat up the next two tokens which must be
1 - the name of the include file, and
2 - a terminating semocolon
Then push the current lexer onto the stack, create a new one from
the include file, and push it onto the stack.
When we hit eof (the t_eof) rule, we pop.
'''
next = self.lexer.token()
lineno = next.lineno
# print('NEXT', next, "next.value", next.value, type(next))
if type(next.value) == str:
incfile = next.value.strip('"')
else:
raise QasmException("Invalid include: must be a quoted string.")
next = self.lexer.token()
if next is None or next.value != ';':
raise QasmException('Invalid syntax, missing ";" at line',
str(lineno))
if not os.path.exists(incfile):
raise QasmException('Include file', incfile,
'cannot be found, line', str(next.lineno),
', file', self.filename)
self.push(incfile)
return self.lexer.token()
def t_MAGIC(self, t):
'OPENQASM'
return t
def t_COMMENT(self, t):
r'//.*'
pass
def t_ID(self, t):
r'[a-zA-Z_][a-zA-Z0-9_]*'
if t.value == 'U':
t.type = 'U'
return t
if t.value == 'CX':
t.type = 'CX'
return t
if t.value == 'pi':
t.type = 'PI'
return t
t.value = Node.Id(t.value, self.lineno, self.filename)
return t
def t_newline(self, t):
r'\n+'
self.lineno += len(t.value)
t.lexer.lineno = self.lineno
def t_eof(self, t):
if len(self.stack) > 0:
self.pop()
return self.lexer.token()
else:
return None
t_ignore = ' \t\r'
def t_error(self, t):
print("Junk in the line -->%s<--" % t.value[0])
# t.lexer.skip(1)

View File

@ -0,0 +1,978 @@
"""
OPENQASM parser.
Author: Jim Challenger
"""
import math
from ._qasmlexer import QasmLexer
import ply.yacc as yacc
from ._qasmexception import QasmException
from . import _node as node
class QasmParser(object):
"""OPENQASM Parser."""
def __init__(self, filename):
"""Create the parser."""
self.lexer = QasmLexer(filename)
self.tokens = self.lexer.tokens
self.parser = yacc.yacc(module=self, debug=True)
self.qasm = None
self.parseDeb = False
self.global_symtab = {} # global symtab
self.current_symtab = self.global_symtab # top of symbol stack
self.symbols = [] # symbol stack
def update_symtab(self, obj):
"""Update a node in the symbol table.
Everything in the symtab must be a node with these attributes:
name - the string name of the object
type - the string type of the object
line - the source line where the type was first found
file - the source file where the type was first found
"""
if obj.name in self.current_symtab:
prev = self.current_symtab[obj.name]
raise QasmException("Duplicate declaretion for", obj.type + " '"
+ obj.name + "' at line", str(obj.line)
+ ', file', obj.file
+ '.\nPrevious occurance at line',
str(prev.line) + ', file', prev.file)
self.current_symtab[obj.name] = obj
def verify_declared_bit(self, obj):
"""Verify a qubit id against the gate prototype."""
# We are verifying gate args against the formal parameters of a
# gate prototype.
if obj.name not in self.current_symtab:
raise QasmException("Cannot find symbol '" + obj.name
+ "' in argument list for gate, line",
str(obj.line), 'file', obj.file)
# This insures the thing is from the bitlist and not from the
# argument list.
sym = self.current_symtab[obj.name]
if not (sym.type == 'id' and sym.is_bit):
raise QasmException("Bit", obj.name,
'is not declared as a bit in the gate.')
def verify_bit_list(self, obj):
"""Verify each qubit in a list of ids."""
# We expect the object to be a bitlist or an idlist, we don't care.
# We will iterate it and insure everything in it is declared as a bit,
# and throw if not.
for b in obj.children:
self.verify_declared_bit(b)
def verify_exp_list(self, obj):
"""Verify each expression in a list."""
# A tad harder. This is a list of expressions each of which could be
# the head of a tree. We need to recursively walk each of these and
# ensure that any Id elements resolve to the current stack.
#
# I believe we only have to look at the current symtab.
if obj.children is not None:
for child in obj.children:
if isinstance(child, node.Id):
if child.name in ['sin', 'cos', 'tan', 'exp',
'ln', 'sqrt']:
continue
if child.name not in self.current_symtab:
raise QasmException("Argument '" + child.name
+ "' in expression cannot be "
+ "found, line", str(child.line),
"file", child.file)
else:
if hasattr(child, "children"):
self.verify_exp_list(child)
def verify_as_gate(self, obj, bitlist, arglist=None):
"""Verify a user defined gate call."""
if obj.name not in self.global_symtab:
raise QasmException("Cannot find gate definition for '" + obj.name
+ "', line", str(obj.line), 'file', obj.file)
g = self.global_symtab[obj.name]
if not (g.type == 'gate' or g.type == 'opaque'):
raise QasmException("'" + obj.name + "' is used as a gate "
+ "or opaque call but the symbol is neither;"
+ " it is a '" + g.type + "' line",
str(obj.line), 'file', obj.file)
if g.n_bits() != bitlist.size():
raise QasmException("Gate or opaque call to '" + obj.name
+ "' uses", str(bitlist.size()),
"qubits but is declared for",
str(g.n_bits()), "qubits", "line",
str(obj.line), 'file', obj.file)
if arglist:
if g.n_args() != arglist.size():
raise QasmException("Gate or opaque call to '" + obj.name
+ "' uses", str(arglist.size()),
"qubits but is declared for",
str(g.n_args()), "qubits", "line",
str(obj.line), 'file', obj.file)
else:
if g.n_args() > 0:
raise QasmException("Gate or opaque call to '" + obj.name
+ "' has no arguments but is declared for",
str(g.n_args()), "qubits", "line",
str(obj.line), 'file', obj.file)
def verify_reg(self, obj, typ):
"""Verify a register."""
# How to verify:
# types must match
# indexes must be checked
if obj.name not in self.global_symtab:
raise QasmException('Cannot find definition for', typ, "'"
+ obj.name + "'", 'at line', str(obj.line),
'file', obj.file)
sym = self.global_symtab[obj.name]
if sym.type != typ:
raise QasmException("Type for '" + sym.name + "' should be '"
+ typ + "' but was found to be '" + sym.type
+ "'", "line", str(obj.line), "file", obj.file)
if obj.type == 'indexed_id':
bound = sym.index
ndx = obj.index
if ndx < 0 or ndx >= bound:
raise QasmException("Register index for '" + sym.name
+ "' out of bounds. Index is", str(ndx),
"bound is 0 <= index <", str(bound),
"at line", str(obj.line), "file", obj.file)
def verify_reg_list(self, obj, typ):
"""Verify a list of registers."""
# We expect the object to be a bitlist or an idlist, we don't care.
# We will iterate it and ensure everything in it is declared as a bit,
# and throw if not.
for b in obj.children:
self.verify_reg(b, typ)
def pop_scope(self):
"""Return to the previous scope."""
self.current_symtab = self.symbols.pop()
def push_scope(self):
"""Enter a new scope."""
self.symbols.append(self.current_symtab)
self.current_symtab = {}
# ---- Begin the PLY parser ----
start = 'main'
def p_main(self, p):
'''
main : program
'''
self.qasm = p[1]
# ----------------------------------------
# program : statement
# | program statement
# ----------------------------------------
def p_program_0(self, p):
'''
program : statement
'''
p[0] = node.Program([p[1]])
def p_program_1(self, p):
'''
program : program statement
'''
p[0] = p[1]
p[0].add_child(p[2])
# ----------------------------------------
# statement : decl
# | quantum_op ';'
# | magic ';'
# ----------------------------------------
def p_statement(self, p):
'''
statement : decl
| quantum_op ';'
| magic ';'
| ignore
| quantum_op error
| magic error
'''
if len(p) > 2:
if p[2] != ';':
raise QasmException("Missing ';' at end of statement; "
+ "received", str(p[2].value))
p[0] = p[1]
def p_magic(self, p):
'''
magic : MAGIC REAL
'''
p[0] = node.Magic([p[2]])
def p_magic_0(self, p):
'''
magic : MAGIC error
'''
magic = "2.0;"
raise QasmException("Invalid magic string. Expected '" + magic
+ "'. Is the semicolon missing?")
# ----------------------------------------
# id : ID
# ----------------------------------------
def p_id(self, p):
'''
id : ID
'''
p[0] = p[1]
def p_id_e(self, p):
'''
id : error
'''
raise QasmException("Expected an ID, received '"
+ str(p[1].value) + "'")
# ----------------------------------------
# indexed_id : ID [ int ]
# ----------------------------------------
def p_indexed_id(self, p):
'''
indexed_id : id '[' NNINTEGER ']'
| id '[' NNINTEGER error
| id '[' error
'''
if len(p) == 4:
raise QasmException("Expecting an integer index; received",
str(p[3].value))
if p[4] != ']':
raise QasmException("Missing ']' in indexed ID; received",
str(p[4].value))
p[0] = node.IndexedId([p[1], p[3]])
# ----------------------------------------
# primary : id
# | indexed_id
# ----------------------------------------
def p_primary(self, p):
'''
primary : id
| indexed_id
'''
p[0] = p[1]
# ----------------------------------------
# id_list : id
# | id_list ',' id
# ----------------------------------------
def p_id_list_0(self, p):
'''
id_list : id
'''
p[0] = node.IdList([p[1]])
def p_id_list_1(self, p):
'''
id_list : id_list ',' id
'''
p[0] = p[1]
p[0].add_child(p[3])
# ----------------------------------------
# gate_id_list : id
# | gate_id_list ',' id
# ----------------------------------------
def p_gate_id_list_0(self, p):
'''
gate_id_list : id
'''
p[0] = node.IdList([p[1]])
self.update_symtab(p[1])
def p_gate_id_list_1(self, p):
'''
gate_id_list : gate_id_list ',' id
'''
p[0] = p[1]
p[0].add_child(p[3])
self.update_symtab(p[3])
# ----------------------------------------
# bit_list : bit
# | bit_list ',' bit
# ----------------------------------------
def p_bit_list_0(self, p):
'''
bit_list : id
'''
p[0] = node.IdList([p[1]])
p[1].is_bit = True
self.update_symtab(p[1])
def p_bit_list_1(self, p):
'''
bit_list : bit_list ',' id
'''
p[0] = p[1]
p[0].add_child(p[3])
p[3].is_bit = True
self.update_symtab(p[3])
# ----------------------------------------
# primary_list : primary
# | primary_list ',' primary
# ----------------------------------------
def p_primary_list_0(self, p):
'''
primary_list : primary
'''
p[0] = node.PrimaryList([p[1]])
def p_primary_list_1(self, p):
'''
primary_list : primary_list ',' primary
'''
p[0] = p[1]
p[1].add_child(p[3])
# ----------------------------------------
# decl : qreg_decl
# | creg_decl
# | gate_decl
# ----------------------------------------
def p_decl(self, p):
'''
decl : qreg_decl ';'
| creg_decl ';'
| qreg_decl error
| creg_decl error
| gate_decl
'''
if len(p) > 2:
if p[2] != ';':
raise QasmException("Missing ';' in qreg or creg declaraton."
+ " Instead received '" + p[2].value + "'")
p[0] = p[1]
# ----------------------------------------
# qreg_decl : QREG indexed_id
# ----------------------------------------
def p_qreg_decl(self, p):
'''
qreg_decl : QREG indexed_id
'''
p[0] = node.Qreg([p[2]])
self.update_symtab(p[0])
def p_qreg_decl_e(self, p):
'''
qreg_decl : QREG error
'''
raise QasmException("Expecting indexed id (ID[int]) in QREG"
+ " declaration; received", p[2].value)
# ----------------------------------------
# creg_decl : QREG indexed_id
# ----------------------------------------
def p_creg_decl(self, p):
'''
creg_decl : CREG indexed_id
'''
p[0] = node.Creg([p[2]])
self.update_symtab(p[0])
def p_creg_decl_e(self, p):
'''
creg_decl : CREG error
'''
raise QasmException("Expecting indexed id (ID[int]) in CREG"
+ " declaration; received", p[2].value)
# Gate_body will throw if there are errors, so we don't need to cover
# that here. Same with the id_lists - if they are not legal, we die
# before we get here
#
# ----------------------------------------
# gate_decl : GATE id gate_scope bit_list gate_body
# | GATE id gate_scope '(' ')' bit_list gate_body
# | GATE id gate_scope '(' gate_id_list ')' bit_list gate_body
#
# ----------------------------------------
def p_gate_decl_0(self, p):
'''
gate_decl : GATE id gate_scope bit_list gate_body
'''
p[0] = node.Gate([p[2], p[4], p[5]])
self.pop_scope()
self.update_symtab(p[0])
def p_gate_decl_1(self, p):
'''
gate_decl : GATE id gate_scope '(' ')' bit_list gate_body
'''
p[0] = node.Gate([p[2], p[6], p[7]])
self.pop_scope()
self.update_symtab(p[0])
def p_gate_decl_2(self, p):
'''
gate_decl : GATE id gate_scope '(' gate_id_list ')' bit_list gate_body
'''
p[0] = node.Gate([p[2], p[5], p[7], p[8]])
self.pop_scope()
self.update_symtab(p[0])
def p_gate_scope(self, p):
'''
gate_scope :
'''
self.push_scope()
# ----------------------------------------
# gate_body : '{' gate_op_list '}'
# | '{' '}'
#
# | '{' gate_op_list error
# | '{' error
#
# Error handling: gete_op will throw if there's a problem so we won't
# get here with in the gate_op_list
# ----------------------------------------
def p_gate_body_0(self, p):
'''
gate_body : '{' '}'
'''
if p[2] != '}':
raise QasmException("Missing '}' in gate definition; received'"
+ str(p[2].value) + "'")
p[0] = node.GateBody(None)
def p_gate_body_1(self, p):
'''
gate_body : '{' gate_op_list '}'
'''
p[0] = node.GateBody(p[2])
# ----------------------------------------
# gate_op_list : gate_op
# | gate_op_ist gate_op
#
# Error handling: gete_op will throw if there's a problem so we won't
# get here with errors
# ----------------------------------------
def p_gate_op_list_0(self, p):
'''
gate_op_list : gate_op
'''
p[0] = [p[1]]
def p_gate_op_list_1(self, p):
'''
gate_op_list : gate_op_list gate_op
'''
p[0] = p[1]
p[0].append(p[2])
# ----------------------------------------
# These are for use outside of gate_bodies and allow
# indexed ids everywhere.
#
# unitary_op : U '(' exp_list ')' primary
# | CX primary ',' primary
# | id pirmary_list
# | id '(' ')' primary_list
# | id '(' exp_list ')' primary_list
#
# Note that it might not be unitary - this is the mechanism that
# is also used to invoke calls to 'opaque'
# ----------------------------------------
def p_unitary_op_0(self, p):
'''
unitary_op : U '(' exp_list ')' primary
'''
p[0] = node.UniversalUnitary([p[3], p[5]])
self.verify_reg(p[5], 'qreg')
self.verify_exp_list(p[3])
def p_unitary_op_1(self, p):
'''
unitary_op : CX primary ',' primary
'''
p[0] = node.Cnot([p[2], p[4]])
self.verify_reg(p[2], 'qreg')
self.verify_reg(p[4], 'qreg')
def p_unitary_op_2(self, p):
'''
unitary_op : id primary_list
'''
p[0] = node.CustomUnitary([p[1], p[2]])
self.verify_as_gate(p[1], p[2])
self.verify_reg_list(p[2], 'qreg')
def p_unitary_op_3(self, p):
'''
unitary_op : id '(' ')' primary_list
'''
p[0] = node.CustomUnitary([p[1], p[4]])
self.verify_as_gate(p[1], p[4])
self.verify_reg_list(p[4], 'qreg')
def p_unitary_op_4(self, p):
'''
unitary_op : id '(' exp_list ')' primary_list
'''
p[0] = node.CustomUnitary([p[1], p[3], p[5]])
self.verify_as_gate(p[1], p[5], arglist=p[3])
self.verify_reg_list(p[5], 'qreg')
self.verify_exp_list(p[3])
# ----------------------------------------
# This is a restricted set of "quantum_op" which also
# prohibits indexed ids, for use in a gate_body
#
# gate_op : U '(' exp_list ')' id ';'
# | CX id ',' id ';'
# | id id_list ';'
# | id '(' ')' id_list ';'
# | id '(' exp_list ')' id_list ';'
# | BARRIER id_list ';'
# ----------------------------------------
def p_gate_op_0(self, p):
'''
gate_op : U '(' exp_list ')' id ';'
'''
p[0] = node.UniversalUnitary([p[3], p[5]])
self.verify_declared_bit(p[5])
self.verify_exp_list(p[3])
def p_gate_op_0e1(self, p):
'''
gate_op : U '(' exp_list ')' error
'''
raise QasmException("Invalid U inside gate definition. "
+ "Missing bit id or ';'")
def p_gate_op_0e2(self, p):
'''
gate_op : U '(' exp_list error
'''
raise QasmException("Missing ')' in U invocation in gate definition.")
def p_gate_op_1(self, p):
'''
gate_op : CX id ',' id ';'
'''
p[0] = node.Cnot([p[2], p[4]])
self.verify_declared_bit(p[2])
self.verify_declared_bit(p[4])
def p_gate_op_1e1(self, p):
'''
gate_op : CX error
'''
raise QasmException("Invalid CX inside gate definition. "
+ "Expected an ID or '.', received '"
+ str(p[2].value) + "'")
def p_gate_op_1e2(self, p):
'''
gate_op : CX id ',' error
'''
raise QasmException("Invalid CX inside gate definition. "
+ "Expected an ID or ';', received '"
+ str(p[4].value) + "'")
def p_gate_op_2(self, p):
'''
gate_op : id id_list ';'
'''
p[0] = node.CustomUnitary([p[1], p[2]])
# To verify:
# 1. id is declared as a gate in global scope
# 2. everything in the id_list is declared as a bit in local scope
self.verify_as_gate(p[1], p[2])
self.verify_bit_list(p[2])
def p_gate_op_2e(self, p):
'''
gate_op : id id_list error
'''
raise QasmException("Invalid gate invocation inside gate definition.")
def p_gate_op_3(self, p):
'''
gate_op : id '(' ')' id_list ';'
'''
p[0] = node.CustomUnitary([p[1], p[4]])
self.verify_as_gate(p[1], p[4])
self.verify_bit_list(p[4])
def p_gate_op_4(self, p):
'''
gate_op : id '(' exp_list ')' id_list ';'
'''
p[0] = node.CustomUnitary([p[1], p[3], p[5]])
self.verify_as_gate(p[1], p[5], arglist=p[3])
self.verify_bit_list(p[5])
self.verify_exp_list(p[3])
def p_gate_op_4e0(self, p):
'''
gate_op : id '(' ')' error
'''
raise QasmException("Invalid bit list inside gate definition or"
+ " missing ';'")
def p_gate_op_4e1(self, p):
'''
gate_op : id '(' error
'''
raise QasmException("Unmatched () for gate invocation inside gate"
+ " invocation.")
def p_gate_op_5(self, p):
'''
gate_op : BARRIER id_list ';'
'''
p[0] = node.Barrier([p[2]])
self.verify_bit_list(p[2])
def p_gate_op_5e(self, p):
'''
gate_op : BARRIER error
'''
raise QasmException("Invalid barrier inside gate definition.")
# ----------------------------------------
# opaque : OPAQUE id gate_scope bit_list
# | OPAQUE id gate_scope '(' ')' bit_list
# | OPAQUE id gate_scope '(' gate_id_list ')' bit_list
#
# These are like gate declaratons only wihtout a body.
# ----------------------------------------
def p_opaque_0(self, p):
'''
opaque : OPAQUE id gate_scope bit_list
'''
p[0] = Opaque([p[2], p[4]])
self.pop_scope()
self.update_symtab(p[0])
def p_opaque_1(self, p):
'''
opaque : OPAQUE id gate_scope '(' ')' bit_list
'''
p[0] = node.Opaque([p[2], p[6]])
self.pop_scope()
self.update_symtab(p[0])
def p_opaque_2(self, p):
'''
opaque : OPAQUE id gate_scope '(' gate_id_list ')' bit_list
'''
p[0] = node.Opaque([p[2], p[5], p[7]])
self.pop_scope()
self.update_symtab(p[0])
def p_opaque_1e(self, p):
'''
opaque : OPAQUE id gate_scope '(' error
'''
raise QasmException("Poorly formed OPAQUE statement.")
# ----------------------------------------
# measure : MEASURE primary ASSIGN primary
# ----------------------------------------
def p_measure(self, p):
'''
measure : MEASURE primary ASSIGN primary
'''
p[0] = node.Measure([p[2], p[4]])
self.verify_reg(p[2], 'qreg')
self.verify_reg(p[4], 'creg')
def p_measure_e(self, p):
'''
measure : MEASURE primary error
'''
raise QasmException("Illegal measure statement." + str(p[3].value))
# ----------------------------------------
# barrier : BARRIER primary_list
#
# Errors are covered by handling erros in primary_list
# ----------------------------------------
def p_barrier(self, p):
'''
barrier : BARRIER primary_list
'''
p[0] = node.Barrier([p[2]])
self.verify_reg_list(p[2], 'qreg')
# ----------------------------------------
# reset : RESET primary
# ----------------------------------------
def p_reset(self, p):
'''
reset : RESET primary
'''
p[0] = node.Reset([p[2]])
self.verify_reg(p[2], 'qreg')
# ----------------------------------------
# IF '(' ID MATCHES NNINTEGER ')' quantum_op
# ----------------------------------------
def p_if(self, p):
'''
if : IF '(' id MATCHES NNINTEGER ')' quantum_op
if : IF '(' id error
if : IF '(' id MATCHES error
if : IF '(' id MATCHES NNINTEGER error
if : IF error
'''
if len(p) == 3:
raise QasmException("Ill-formed IF statement. Perhaps a"
+ " missing '('?")
if len(p) == 5:
raise QasmException("Ill-formed IF statement. Expected '==', "
+ "received '" + str(p[4].value))
if len(p) == 6:
raise QasmException("Ill-formed IF statement. Expected a number, "
+ "received '" + str(p[5].value))
if len(p) == 7:
raise QasmException("Ill-formed IF statement, unmatched '('")
p[0] = node.If([p[3], p[5], p[7]])
# ----------------------------------------
# These are all the things you can have outside of a gate declaration
# quantum_op : unitary_op
# | opaque
# | measure
# | reset
# | barrier
# | if
#
# ----------------------------------------
def p_quantum_op(self, p):
'''
quantum_op : unitary_op
| opaque
| measure
| barrier
| reset
| if
'''
p[0] = p[1]
# ----------------------------------------
# unary : NNINTEGER
# | REAL
# | PI
# | ID
# | '(' expression ')'
# | id '(' expression ')'
#
# We will trust 'expression' to throw before we have to handle it here
# ----------------------------------------
def p_unary_0(self, p):
'''
unary : NNINTEGER
'''
p[0] = node.Int(p[1])
def p_unary_1(self, p):
'''
unary : REAL
'''
p[0] = node.Real(p[1])
def p_unary_2(self, p):
'''
unary : PI
'''
p[0] = node.Real(math.pi)
def p_unary_3(self, p):
'''
unary : id
'''
p[0] = p[1]
def p_unary_4(self, p):
'''
unary : '(' expression ')'
'''
p[0] = p[2]
def p_unary_6(self, p):
'''
unary : id '(' expression ')'
'''
# note this is a semantic check, not syntactic
if p[1].name not in ['sin', 'cos', 'tan', 'exp', 'ln', 'sqrt']:
raise QasmException("Illegal external function call: ",
str(p[1].name))
p[0] = node.External([p[1], p[3]])
# ----------------------------------------
# Prefix
# ----------------------------------------
def p_prefix_expression_0(self, p):
'''
prefix_expression : unary
'''
p[0] = p[1]
def p_prefix_expression_1(self, p):
'''
prefix_expression : '+' prefix_expression
| '-' prefix_expression
'''
p[0] = node.Prefix([p[1], p[2]])
def p_additive_expression_0(self, p):
'''
additive_expression : prefix_expression
'''
p[0] = p[1]
def p_additive_expression_1(self, p):
'''
additive_expression : additive_expression '+' prefix_expression
| additive_expression '-' prefix_expression
'''
p[0] = node.BinaryOp([p[2], p[1], p[3]])
def p_multiplicative_expression_0(self, p):
'''
multiplicative_expression : additive_expression
'''
p[0] = p[1]
def p_multiplicative_expression_1(self, p):
'''
multiplicative_expression : multiplicative_expression '*' additive_expression
| multiplicative_expression '/' additive_expression
'''
p[0] = node.BinaryOp([p[2], p[1], p[3]])
def p_expression_0(self, p):
'''
expression : multiplicative_expression
'''
p[0] = p[1]
def p_expression_1(self, p):
'''
expression : expression '^' multiplicative_expression
'''
p[0] = node.BinaryOp([p[2], p[1], p[3]])
# ----------------------------------------
# exp_list : exp
# | exp_list ',' exp
# ----------------------------------------
def p_exp_list_0(self, p):
'''
exp_list : expression
'''
p[0] = node.ExpressionList([p[1]])
def p_exp_list_1(self, p):
'''
exp_list : exp_list ',' expression
'''
p[0] = p[1]
p[0].add_child(p[3])
def p_ignore(self, p):
'''
ignore : STRING
'''
# this should never hit but it keeps the unsupressable warnings at bay
pass
def p_error(self, p):
# EOF is a special case because the stupid error token isn't placed
# on the stack
if not p:
raise QasmException("Error at end of file. "
+ "Perhaps there is a missing ';'")
col = self.find_column(self.lexer.data, p)
print("Error near line", str(self.lexer.lineno), 'Column', col)
def find_column(self, input, token):
"""Compute the column.
Input is the input text string.
token is a token instance.
"""
if token is None:
return 0
last_cr = input.rfind('\n', 0, token.lexpos)
if last_cr < 0:
last_cr = 0
column = (token.lexpos - last_cr) + 1
return column
def print_tokens(self):
'''Test method to verify tokenizer.'''
try:
while True:
tok = self.lexer.token()
if not tok:
break
# TODO: This isn't really the column, it's the character
# position. Need to do backtrack to the nearest \n to get
# the actual column.
print('TOKEN:' + str(tok) + ":ENDTOKEN", 'at line',
tok.lineno, 'column', tok.lexpos, 'file',
self.lexer.filename)
except QasmException as e:
print('Exception tokenizing qasm file:', e.msg)
def parse_debug(self, val):
"""Set the parseDeb field."""
if val is True:
self.parseDeb = True
elif val is False:
self.parseDeb = False
else:
raise QasmException("Illegal debug value '" + str(val)
+ "' must be True or False.")
def parse(self, data):
"""Parse some data."""
self.parser.parse(data, lexer=self.lexer, debug=self.parseDeb)
if self.qasm is None:
raise QasmException("Uncaught exception in parser; "
+ "see previous messages for details.")
return self.qasm
def print_tree(self):
"""Print parsed OPENQASM."""
if self.qasm is not None:
self.qasm.to_string(0)
else:
print("No parsed qasm to print")
def run(self, data):
"""Parser runner.
To use this module stand-alone.
"""
ast = self.parser.parse(data, debug=True)
self.parser.parse(data, debug=True)
ast.to_string(0)

Some files were not shown because too many files have changed in this diff Show More