diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..2b55ac9a5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "quillang"] + path = docs/quil + url = https://github.com/rigetti/quil.git diff --git a/Makefile b/Makefile index 0d485e341..ca6d9fab7 100644 --- a/Makefile +++ b/Makefile @@ -80,3 +80,11 @@ upload: .PHONY: version version: @git describe --tags | sed 's/v//' | sed 's/\(.*\)-.*/\1/'| sed 's/-/./' + +docs/quil/grammars/Quil.g4: + git submodule init + git submodule update + +.PHONY: generate-parser +generate-parser: docs/quil/grammars/Quil.g4 + cd docs/quil/grammars && antlr -Dlanguage=Python3 -o ../../../pyquil/_parser/gen3 Quil.g4 diff --git a/docs/quil b/docs/quil new file mode 160000 index 000000000..634404fc3 --- /dev/null +++ b/docs/quil @@ -0,0 +1 @@ +Subproject commit 634404fc3b41b1c660b485f959dc84ca52ccfd36 diff --git a/pyquil/_parser/Quil.g4 b/pyquil/_parser/Quil.g4 deleted file mode 100644 index bda41b0a8..000000000 --- a/pyquil/_parser/Quil.g4 +++ /dev/null @@ -1,354 +0,0 @@ -grammar Quil; - -//////////////////// -// PARSER -//////////////////// - -quil : allInstr? ( NEWLINE+ allInstr )* NEWLINE* EOF ; - -allInstr : defGate - | defGateAsPauli - | defCircuit - | defFrame - | defWaveform - | defCalibration - | defMeasCalibration - | instr - ; - -instr : fence - | fenceAll - | delay - | gate - | measure - | defLabel - | halt - | jump - | jumpWhen - | jumpUnless - | resetState - | wait - | classicalUnary - | classicalBinary - | classicalComparison - | load - | store - | nop - | include - | pragma - | pulse - | setFrequency - | shiftFrequency - | setPhase - | shiftPhase - | swapPhase - | setScale - | capture - | rawCapture - | memoryDescriptor // this is a little unusual, but it's in steven's example - ; - -// C. Static and Parametric Gates - -gate : modifier* name ( LPAREN param ( COMMA param )* RPAREN )? qubit+ ; - -name : IDENTIFIER ; -qubit : INT ; - -param : expression ; - -modifier : CONTROLLED - | DAGGER - | FORKED ; - -// D. Gate Definitions - -defGate : DEFGATE name (( LPAREN variable ( COMMA variable )* RPAREN ) | ( AS gatetype ))? COLON NEWLINE matrix ; -defGateAsPauli : DEFGATE name ( LPAREN variable ( COMMA variable )* RPAREN )? qubitVariable+ AS PAULISUM COLON NEWLINE pauliTerms ; - -variable : PERCENTAGE IDENTIFIER ; -gatetype : MATRIX - | PERMUTATION ; - -matrix : ( matrixRow NEWLINE )* matrixRow ; -matrixRow : TAB expression ( COMMA expression )* ; - -pauliTerms : ( pauliTerm NEWLINE )* pauliTerm; -pauliTerm : TAB IDENTIFIER LPAREN expression RPAREN qubitVariable+ ; - -// E. Circuits - -defCircuit : DEFCIRCUIT name ( LPAREN variable ( COMMA variable )* RPAREN )? qubitVariable* COLON NEWLINE circuit ; - -qubitVariable : IDENTIFIER ; - -circuitQubit : qubit | qubitVariable ; -circuitGate : name ( LPAREN param ( COMMA param )* RPAREN )? circuitQubit+ ; -circuitMeasure : MEASURE circuitQubit addr? ; -circuitResetState : RESET circuitQubit? ; -circuitInstr : circuitGate | circuitMeasure | circuitResetState | instr ; -circuit : ( TAB circuitInstr NEWLINE )* TAB circuitInstr ; - -// F. Measurement - -measure : MEASURE qubit addr? ; -addr : IDENTIFIER | ( IDENTIFIER? LBRACKET INT RBRACKET ); - -// G. Program control - -defLabel : LABEL label ; -label : AT IDENTIFIER ; -halt : HALT ; -jump : JUMP label ; -jumpWhen : JUMPWHEN label addr ; -jumpUnless : JUMPUNLESS label addr ; - -// H. Zeroing the Quantum State - -resetState : RESET qubit? ; // NB: cannot be named "reset" due to conflict with Antlr implementation - -// I. Classical/Quantum Synchronization - -wait : WAIT ; - -// J. Classical Instructions - -memoryDescriptor : DECLARE IDENTIFIER IDENTIFIER ( LBRACKET INT RBRACKET )? ( SHARING IDENTIFIER ( offsetDescriptor )* )? ; -offsetDescriptor : OFFSET INT IDENTIFIER ; - -classicalUnary : ( NEG | NOT | TRUE | FALSE ) addr ; -classicalBinary : logicalBinaryOp | arithmeticBinaryOp | move | exchange | convert ; -logicalBinaryOp : ( AND | OR | IOR | XOR ) addr ( addr | INT ) ; -arithmeticBinaryOp : ( ADD | SUB | MUL | DIV ) addr ( addr | number ) ; -move : MOVE addr ( addr | number ); -exchange : EXCHANGE addr addr ; -convert : CONVERT addr addr ; -load : LOAD addr IDENTIFIER addr ; -store : STORE IDENTIFIER addr ( addr | number ); -classicalComparison : ( EQ | GT | GE | LT | LE ) addr addr ( addr | number ); - -// K. The No-Operation Instruction - -nop : NOP ; - -// L. File Inclusion - -include : INCLUDE STRING ; - -// M. Pragma Support - -pragma : PRAGMA ( IDENTIFIER | keyword ) pragma_name* STRING? ; -pragma_name : IDENTIFIER | keyword | INT ; - -// Expressions (in order of precedence) - -expression : LPAREN expression RPAREN #parenthesisExp - | sign expression #signedExp - | expression POWER expression #powerExp - | expression ( TIMES | DIVIDE ) expression #mulDivExp - | expression ( PLUS | MINUS ) expression #addSubExp - | function LPAREN expression RPAREN #functionExp - | number #numberExp - | variable #variableExp - | addr #addrExp - ; - -function : SIN | COS | SQRT | EXP | CIS ; -sign : PLUS | MINUS ; - -// Numbers -// We suffix -N onto these names so they don't conflict with already defined Python types - -number : MINUS? ( realN | imaginaryN | I | PI ) ; -imaginaryN : realN I ; -realN : FLOAT | INT ; - -// Analog control - -waveformName : name (DIVIDE name)? ; - -defFrame : DEFFRAME frame ( COLON frameSpec+ )? ; -frameSpec : NEWLINE TAB frameAttr COLON ( expression | STRING ) ; -frameAttr : SAMPLERATE | INITIALFREQUENCY | DIRECTION | HARDWAREOBJECT | CENTERFREQUENCY; - -defWaveform : DEFWAVEFORM waveformName ( LPAREN param (COMMA param)* RPAREN )? COLON NEWLINE matrix ; -defCalibration : DEFCAL name (LPAREN param ( COMMA param )* RPAREN)? qubitOrFormal+ COLON ( NEWLINE TAB instr )* ; -defMeasCalibration : DEFCAL MEASURE qubitOrFormal ( name )? COLON ( NEWLINE TAB instr )* ; - -pulse : NONBLOCKING? PULSE frame waveform ; -capture : NONBLOCKING? CAPTURE frame waveform addr ; -rawCapture : NONBLOCKING? RAWCAPTURE frame expression addr ; - -setFrequency : SETFREQUENCY frame expression ; -shiftFrequency : SHIFTFREQUENCY frame expression ; -setPhase : SETPHASE frame expression ; -shiftPhase : SHIFTPHASE frame expression ; -swapPhase : SWAPPHASE frame frame ; -setScale : SETSCALE frame expression ; - -delay : DELAY qubitOrFormal+ STRING* expression ; -fenceAll : FENCE ; -fence : FENCE qubitOrFormal+ ; - -qubitOrFormal : qubit | qubitVariable ; -namedParam : IDENTIFIER COLON expression ; -waveform : waveformName (LPAREN namedParam ( COMMA namedParam )* RPAREN)? ; -frame : qubitOrFormal+ STRING ; - -// built-in waveform types include: "flat", "gaussian", "draggaussian", "erfsquare" - - -//////////////////// -// LEXER -//////////////////// - -keyword : DEFGATE | DEFCIRCUIT | MEASURE | LABEL | HALT | JUMP | JUMPWHEN | JUMPUNLESS - | RESET | WAIT | NOP | INCLUDE | PRAGMA | DECLARE | SHARING | OFFSET | AS | MATRIX - | PERMUTATION | NEG | NOT | TRUE | FALSE | AND | IOR | XOR | OR | ADD | SUB | MUL - | DIV | MOVE | EXCHANGE | CONVERT | EQ | GT | GE | LT | LE | LOAD | STORE | PI | I - | SIN | COS | SQRT | EXP | CIS | CAPTURE | DEFCAL | DEFFRAME | DEFWAVEFORM - | DELAY | DIRECTION | FENCE | INITIALFREQUENCY | CENTERFREQUENCY | NONBLOCKING | PULSE | SAMPLERATE - | SETFREQUENCY | SETPHASE | SETSCALE | SHIFTPHASE | SWAPPHASE | RAWCAPTURE - | CONTROLLED | DAGGER | FORKED ; - -// Keywords - -DEFGATE : 'DEFGATE' ; -DEFCIRCUIT : 'DEFCIRCUIT' ; -MEASURE : 'MEASURE' ; - -LABEL : 'LABEL' ; -HALT : 'HALT' ; -JUMP : 'JUMP' ; -JUMPWHEN : 'JUMP-WHEN' ; -JUMPUNLESS : 'JUMP-UNLESS' ; - -RESET : 'RESET' ; -WAIT : 'WAIT' ; -NOP : 'NOP' ; -INCLUDE : 'INCLUDE' ; -PRAGMA : 'PRAGMA' ; - -DECLARE : 'DECLARE' ; -SHARING : 'SHARING' ; -OFFSET : 'OFFSET' ; - -AS : 'AS' ; -MATRIX : 'MATRIX' ; -PERMUTATION : 'PERMUTATION' ; -PAULISUM : 'PAULI-SUM'; - -NEG : 'NEG' ; -NOT : 'NOT' ; -TRUE : 'TRUE' ; // Deprecated -FALSE : 'FALSE' ; // Deprecated - -AND : 'AND' ; -IOR : 'IOR' ; -XOR : 'XOR' ; -OR : 'OR' ; // Deprecated - -ADD : 'ADD' ; -SUB : 'SUB' ; -MUL : 'MUL' ; -DIV : 'DIV' ; - -MOVE : 'MOVE' ; -EXCHANGE : 'EXCHANGE' ; -CONVERT : 'CONVERT' ; - -EQ : 'EQ'; -GT : 'GT'; -GE : 'GE'; -LT : 'LT'; -LE : 'LE'; - -LOAD : 'LOAD' ; -STORE : 'STORE' ; - -PI : 'pi' ; -I : 'i' ; - -SIN : 'SIN' ; -COS : 'COS' ; -SQRT : 'SQRT' ; -EXP : 'EXP' ; -CIS : 'CIS' ; - -// Operators - -PLUS : '+' ; -MINUS : '-' ; -TIMES : '*' ; -DIVIDE : '/' ; -POWER : '^' ; - -// analog keywords - -CAPTURE : 'CAPTURE' ; -DEFCAL : 'DEFCAL' ; -DEFFRAME : 'DEFFRAME' ; -DEFWAVEFORM : 'DEFWAVEFORM' ; -DELAY : 'DELAY' ; -DIRECTION : 'DIRECTION' ; -FENCE : 'FENCE' ; -HARDWAREOBJECT : 'HARDWARE-OBJECT' ; -INITIALFREQUENCY : 'INITIAL-FREQUENCY' ; -CENTERFREQUENCY : 'CENTER-FREQUENCY' ; -NONBLOCKING : 'NONBLOCKING' ; -PULSE : 'PULSE' ; -SAMPLERATE : 'SAMPLE-RATE' ; -SETFREQUENCY : 'SET-FREQUENCY' ; -SHIFTFREQUENCY : 'SHIFT-FREQUENCY' ; -SETPHASE : 'SET-PHASE' ; -SETSCALE : 'SET-SCALE' ; -SHIFTPHASE : 'SHIFT-PHASE' ; -SWAPPHASE : 'SWAP-PHASE' ; -RAWCAPTURE : 'RAW-CAPTURE' ; - -// Modifiers - -CONTROLLED : 'CONTROLLED' ; -DAGGER : 'DAGGER' ; -FORKED : 'FORKED' ; - -// Identifiers - -IDENTIFIER : ( ( [A-Za-z_] ) | ( [A-Za-z_] [A-Za-z0-9\-_]* [A-Za-z0-9_] ) ) ; - -// Numbers - -INT : [0-9]+ ; -FLOAT : [0-9]+ ( '.' [0-9]+ )? ( ( 'e'|'E' ) ( '+' | '-' )? [0-9]+ )? ; - -// String - -STRING : '"' ~( '\n' | '\r' | '"' )* '"'; - -// Punctuation - -PERIOD : '.' ; -COMMA : ',' ; -LPAREN : '(' ; -RPAREN : ')' ; -LBRACKET : '[' ; -RBRACKET : ']' ; -COLON : ':' ; -PERCENTAGE : '%' ; -AT : '@' ; -QUOTE : '"' ; -UNDERSCORE : '_' ; - -// Whitespace - -TAB : ' ' ; -NEWLINE : (' ' | '\t' )* ( '\r'? '\n' | '\r' )+ ; - -// Skips - -COMMENT : (' ' | '\t' )* '#' ~( '\n' | '\r' )* -> skip ; -SPACE : ' ' -> skip ; - -// Error - -INVALID : . ; diff --git a/pyquil/_parser/Quil.g4 b/pyquil/_parser/Quil.g4 new file mode 120000 index 000000000..ed5c54572 --- /dev/null +++ b/pyquil/_parser/Quil.g4 @@ -0,0 +1 @@ +../../docs/quil/grammars/Quil.g4 \ No newline at end of file diff --git a/pyquil/_parser/README.md b/pyquil/_parser/README.md index 94fe04c52..7a310397d 100644 --- a/pyquil/_parser/README.md +++ b/pyquil/_parser/README.md @@ -4,24 +4,37 @@ The Quil Parser Introduction ------------ -This package contains a number of items useful for parsing Quil programs, both with or without -pyQuil. It uses the ANTLR4 parser generator framework. - -`Quil.g4` - This is the definitive reference grammar for Quil as described in the Quil paper. -It is used to generate the Python parser as well as parsers in other programming languages. - -`PyQuilListener.py` - When the parser successfully consumes a Quil program it invokes various -callbacks after encountering different parts of the AST (gates, expressions, etc). This is the -code that creates the pyQuil instructions. - -`gen3/` - Generated parser code for Python 3. Should be checked in but not hand modified. +This package contains a number of items useful for parsing Quil +programs, both with or without pyQuil. It uses the ANTLR4 parser +generator framework. + +`Quil.g4` - The reference grammar for Quil. This is a [symbolic +link](https://en.wikipedia.org/wiki/Symbolic_link) which points to a +[git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) +found in `docs/quil`. Formerly, the grammar lived in this package, +but, to prevent duplication, was moved to a [canonical +location](https://github.com/rigetti/quil/tree/master/grammars). The +grammar is used to generate the Python parser, and may also be used to +generate parsers in any language that has support for ANTLR4 (see +below). + +`PyQuilListener.py` - When the parser successfully consumes a Quil +program it invokes various callbacks after encountering different +parts of the AST (gates, expressions, etc). This is the code that +creates the pyQuil instructions. + +`gen3/` - Generated parser code for Python 3. Should be checked in but +not hand modified. Running ANTLR ------------- -1. Install [ANTLR4](http://www.antlr.org/) and alias it to `antlr4` -2. Navigate to this directory (`pyquil/_parser`) -3. Generate the Python 3 parser code: `antlr4 -Dlanguage=Python3 -o gen3 Quil.g4` +1. Install [ANTLR4](http://www.antlr.org/) +2. Navigate to the top-level pyQuil directory +3. Generate the Python 3 parser code: `make generate-parser` + +Step (3) will do the work of initializing and populating the +`docs/quil` submodule. References ----------