Browse Source

Refactor project

- Begin progress on interpreter (rebuild in C)
- Remove yacc + flex (too much complexity)
- We will port from python to C, in theory this should be a trivial matter
- Right now the interpreter handles one command INIT
master
watkinsr 3 years ago
parent
commit
a9aef1754a
  1. 23
      README.org
  2. 1
      VERSION.txt
  3. 9
      compile
  4. 2
      examples/ex1.sqasm
  5. 9
      examples/test.sqasm
  6. 18
      include/parse.h
  7. 44
      src/Makefile
  8. 9
      src/compile
  9. 70
      src/compile.sh
  10. 25
      src/lex.l
  11. 1863
      src/lex.yy.c
  12. 157
      src/parse.c
  13. 329
      src/parser.y
  14. BIN
      src/qasm
  15. 0
      src/sim/sim.py
  16. 1892
      src/y.tab.c
  17. 97
      src/y.tab.h

23
README.org

@ -1,13 +1,17 @@
# -*- mode: org; -*-
* Prerequisites
+ Flex/Bison
+ Python 2.7
+ Numpy(Python 2.7)
- python2.7
- python-numpy
- python dev libs
- gcc
* Build
./src/compile.sh
* Usage
#+BEGIN_SRC shell
compile foo.SQASM
bin/qasm
#+END_SRC
* Description
Currently this implements some quantum gates and quantum adder operations as found in research papers.
* Example input(HADAMARD -> CNOT)
#+BEGIN_SRC
INITIALIZE R 2 0
@ -16,12 +20,11 @@ APPLY U R
APPLY CNOT R
PEEK R RES
#+END_SRC
* TODOS
+ Package for Python
+ Wiki docs
+ Rewrite in GNU Guile
+ Include quantum algorithms
+ Rewrite simulator to be fully quantum circuit driven
- Rebuild in C
- Nice to have: Include quantum algorithms
- Rewrite simulator to be fully quantum circuit driven
* Documentation
+ [[https://github.com/watkinsr/sqasm-thesis/blob/master/thesis/thesis.pdf][Thesis]]

1
VERSION.txt

@ -1 +0,0 @@
0.2

9
compile

@ -1,9 +0,0 @@
#!/bin/bash
if [ -z "$1" ]
then
echo "ERROR: No input given"
fi
yacc -d parser.y && lex lex.l && gcc -I/usr/include/python2.7 -lpython2.7 lex.yy.c y.tab.c -o qasm
echo "./qasm<$1" >> sqasm.log

2
examples/ex1.sqasm

@ -1,4 +1,4 @@
INITIALIZE R 2 0
INITIALIZE R2 2 0
U TENSOR HAD ID
APPLY U R
SELECT S1 R 0 1

9
examples/test.sqasm

@ -0,0 +1,9 @@
INITIALIZE R2 2 0
U TENSOR HAD ID
APPLY U R
SELECT S1 R 0 1
MEASURE S1 RES
APPLY CNOT R
MEASURE R RES
ADD 3 2 R2
MEASURE R2 RES

18
include/parse.h

@ -0,0 +1,18 @@
#define LSH_RL_BUFSIZE 1024
#define LSH_TOK_BUFSIZE 64
#define LSH_TOK_DELIM " \t\r\n\a"
void lsh_loop(void);
char *lsh_read_line(void);
char **lsh_split_line(char *line);
int lsh_exit(char **args);
int lsh_init(char **args);
char *tokens[] = {
"INIT"};
int (*builtin_func[])(char **) = {
&lsh_init};
// &lsh_u,
// &lsh_apply};

44
src/Makefile

@ -0,0 +1,44 @@
##
# K&R Solutions
#
# @file
# @version 0.1
IDIR =../include
CC=gcc
CFLAGS=-I$(IDIR)
LIBS=-lm
ODIR=obj
LDIR =../lib
BDIR=../bin
_DEPS = parse.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_OBJ = parse.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o [email protected] $< $(CFLAGS)
MKDIR_P = mkdir -p
.PHONY: clean directories
all: directories parse
parse: $(OBJ)
$(CC) -o $(BDIR)/[email protected] $^ $(CFLAGS) $(LIBS)
directories: ${BDIR} ${ODIR}
${BDIR}:
${MKDIR_P} ${BDIR}
${ODIR}:
${MKDIR_P} ${ODIR}
clean:
rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~

9
src/compile

@ -1,9 +0,0 @@
#!/bin/bash
if [ -z "$1" ]
then
echo "ERROR: No input given"
fi
echo yacc -d parser.y && flex lex.l && gcc -I/usr/include/python2.7 -lpython2.7 lex.yy.c y.tab.c -o qasm >> sqasm.log
echo ./qasm<$1 >> sqasm.log

70
src/compile.sh

@ -0,0 +1,70 @@
#!/bin/bash
function run () {
# echo "yacc -d parser.y";
yacc -d parser.y;
# echo "flex lex.l"
flex lex.l;
mv lex.yy.c lexer.c;
mv y.tab.c parser.c;
mv y.tab.h parser.h;
mkdir -p obj;
gcc -Wall -I/usr/include/python2.7 -c parser.c;
gcc -Wall -I/usr/include/python2.7 -c lexer.c;
mv lexer.o obj/lexer.o;
mv parser.o obj/parser.o;
mkdir -p ../bin;
gcc obj/lexer.o obj/parser.o -lpython2.7 -o ../bin/qasm;
# cleanup
rm lexer.c;
rm parser.c;
# rm parser.h;
rm obj/*.o;
}
if ! command -v yacc &> /dev/null
then
echo "yacc could not be found"
echo "Trying to install bison (if you are on debian-based systems)"
sudo apt install bison;
exit
fi
if ! command -v flex &> /dev/null
then
echo "flex could not be found"
echo "Trying to install flex (if you are on debian-based systems)"
sudo apt install flex;
exit
fi
if ! command -v gcc &> /dev/null
then
echo "gcc could not be found"
echo "Trying to install gcc (if you are on debian-based systems)"
sudo apt install gcc;
exit
fi
if ! command -v python2.7 &> /dev/null
then
echo "python2.7 could not be found"
echo "Trying to install python2.7 (if you are on debian-based systems)"
sudo apt install python2.7;
exit
fi
sudo apt install python-numpy;
if [ -d "/usr/include/python2.7" ]; then
run
else
echo "Trying to install libpython libs (if you are on debian-based systems)"
sudo apt install libpython-all-dev
run
fi

25
src/lex.l

@ -1,25 +0,0 @@
%{
#include "y.tab.h"
int yylex();
void yyerror (const char *s);
%}
%%
"printf" {return print;}
"ret" {return exit_command;}
"INITIALIZE" {return init;}
"TENSOR" {return tensor;}
"APPLY" {return apply;}
"SELECT" {return sel;}
"MEASURE" {return measure;}
"ADD" {return add;}
"PEEK" {return peek;}
"HAD"|"ID"|"CNOT"|"SWAP"|"NOT"|"COEF"|"CV"|"COEF2"|"CVPLUS" {yylval.id = strdup(yytext); return gate;}
[0-9]+ {yylval.num = atoi(yytext); return number;}
[A-Z0-9]+ {yylval.id = strdup(yytext); return identifier;}
[ \t\n] ;
[-+=;] {return yytext[0];}
. {ECHO; yyerror ("unexpected character");}
%%
int yywrap (void) {return 1;}

1863
src/lex.yy.c

File diff suppressed because it is too large

157
src/parse.c

@ -0,0 +1,157 @@
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../include/parse.h"
// Taken from: https://brennan.io/2015/01/16/write-a-shell-in-c/
int main(int argc, char **argv)
{
// Load config files, if any.
// Run command loop.
lsh_loop();
// Perform any shutdown/cleanup.
return 0;
}
void lsh_loop(void)
{
char *line;
char **args;
int status;
do
{
printf("> ");
line = lsh_read_line();
args = lsh_split_line(line);
status = lsh_execute(args);
free(line);
free(args);
} while (status);
}
char *lsh_read_line(void)
{
char *line = NULL;
ssize_t bufsize = 0; // have getline allocate a buffer for us
if (getline(&line, &bufsize, stdin) == -1)
{
if (feof(stdin))
{
exit(EXIT_SUCCESS); // We recieved an EOF
}
else
{
perror("readline");
exit(EXIT_FAILURE);
}
}
return line;
}
char **lsh_split_line(char *line)
{
int bufsize = LSH_TOK_BUFSIZE;
int position = 0;
char **tokens = malloc(bufsize * sizeof(char *));
char *token;
if (!tokens)
{
fprintf(stderr, "lsh: allocation error\n");
exit(EXIT_FAILURE);
}
token = strtok(line, LSH_TOK_DELIM);
while (token != NULL)
{
printf("token: %s\n", token);
tokens[position++] = token;
if (position >= bufsize)
{
bufsize += LSH_TOK_BUFSIZE;
tokens = realloc(tokens, bufsize * sizeof(char *));
if (!tokens)
{
fprintf(stderr, "lsh: allocation error\n");
exit(EXIT_FAILURE);
}
}
token = strtok(NULL, LSH_TOK_DELIM);
}
tokens[position] = NULL;
return tokens;
}
/*
List of builtin commands, followed by their corresponding functions.
*/
int lsh_num_builtins()
{
return sizeof(tokens) / sizeof(char *);
}
int lsh_init(char **args)
{
if (args[1] == NULL)
{
fprintf(stderr, "we require a register to INIT, example: INIT R2 2 0\n");
}
else
{
printf("Received a register\n");
}
return 1;
}
/*
Builtin function implementations.
*/
int lsh_help(char **args)
{
int i;
printf("Welcome to this simple quantum interpreter (SQINT)");
printf("Consult examples for example program text");
return 1;
}
int lsh_exit(char **args)
{
return 0;
}
int lsh_execute(char **args)
{
int i;
if (args[0] == NULL)
{
// An empty command was entered.
return 1;
}
for (i = 0; i < lsh_num_builtins(); i++)
{
if (strcmp(args[0], tokens[i]) == 0)
{
return (*builtin_func[i])(args);
}
}
// return lsh_launch(args);
}

329
src/parser.y

@ -1,329 +0,0 @@
%{
#define _XOPEN_SOURCE 500 /* Enable certain library functions (strdup) on linux */
#include "Python.h"
#include <stdio.h> /* C declarations used in actions */
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
int yylex();
void yyerror (const char *s);
/* Purely hashtable */
struct entry_s {
char *key;
PyObject *value;
struct entry_s *next;
};
typedef struct entry_s entry_t;
struct hashtable_s {
int size;
struct entry_s **table;
};
typedef struct hashtable_s hashtable_t;
hashtable_t *hashtable;
hashtable_t *ht_create( int size );
int ht_hash( hashtable_t *hashtable, char *key );
entry_t *ht_newpair( char *key, PyObject *value );
void ht_set( hashtable_t *hashtable, char *key, PyObject *value );
PyObject *ht_get( hashtable_t *hashtable, char *key );
/* Purely Python C-API */
char str[15]; char str2[15];
PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *presult, *tup, *v, *v2;
PyObject* callpy(char* f_name, PyObject* tup);
PyObject* get_pytup(void* a1, void* a2, void* a3, char* t1, char* t2, char* t3, int n_args);
PyObject* call_pyfunc();
int set_tupitem(char* type, void* item, int pos);
%}
%union {int num; char* id;} /* Yacc definitions */
%start line
%token print
%token exit_command
%token init
%token tensor
%token sel
%token measure
%token add
%token peek
%token <id> gate
%token apply
%token <num> number
%token <id> identifier
%type <num> line exp term
%type <id> assignment
%%
/* descriptions of expected inputs corresponding actions (in C) */
line : assignment {;}
| exit_command {exit(EXIT_SUCCESS);}
| print exp {printf("Printing %d\n", $2);}
| line assignment {;}
| line print exp {printf("Printing %d\n", $3);}
| line exit_command {exit(EXIT_SUCCESS);}
| line exp {;}
| exp {;}
;
assignment : init term term term {
printf("\n<INPUT: INIT %s %i %i>\n", $2, $3, $4);
tup = get_pytup($3, $4, " ", "int", "int", NULL, 2);
ht_set(hashtable, $2, callpy("INITIALIZE", tup));
ht_get( hashtable, $2 );
}
;
exp : term {$$ = $1;}
| exp '+' term {$$ = $1 + $3;}
| exp '-' term {$$ = $1 - $3;}
| add term term term {
printf("\n<INPUT: ADD %i %i %s>\n", $2, $3, $4);
tup=get_pytup($2, $3, " ", "int", "int", " ", 2);
ht_set(hashtable, $4, callpy("ADD", tup));
ht_get( hashtable, $4 );
}
| term tensor gate gate {
printf("<INPUT: %s TENSOR %s %s>\n", $1, $3, $4);
tup = get_pytup($3, $4, " ", "str", "str", NULL, 2);
ht_set(hashtable, $1, callpy("t", tup));
ht_get( hashtable, $1 );
}
| term tensor term term {
printf("<INPUT: %s TENSOR %s %s>\n", $1, $3, $4);
tup = get_pytup(ht_get(hashtable, $3), ht_get(hashtable, $4), " ", "py", "py", NULL, 2);
ht_set(hashtable, $1, callpy("t", tup));
ht_get( hashtable, $3 );
}
| apply term term {
printf("<INPUT: APPLY %s %s>\n", $2, $3);
tup = get_pytup(ht_get(hashtable, $2), ht_get(hashtable, $3), " ", "py", "py", NULL, 2);
ht_set(hashtable, $3, callpy("APPLY", tup));
ht_get( hashtable, $3 );
}
| apply gate term {
printf("<INPUT: APPLY GATE TERM>\n", $2, $3);
tup = get_pytup($2, ht_get(hashtable, $3), " ", "str", "py", NULL, 2);
ht_set(hashtable, $3, callpy("APPLY", tup));
ht_get( hashtable, $3 );
}
| measure term term {
printf("<INPUT: MEASURE %s %s", $2, $3);
printf(">\n");
tup = get_pytup(ht_get(hashtable, $2), " ", " ", "py", NULL, NULL, 1);
ht_set(hashtable, $3, callpy("MEASURE", tup));
ht_get( hashtable, $3 );
}
| peek term term {
printf("<INPUT: PEEK %s %s", $2, $3);
tup = get_pytup(ht_get(hashtable, $2), " ", " ", "py", NULL, NULL, 1);
ht_set(hashtable, $3, callpy("PEEK", tup));
ht_get( hashtable, $3 );
}
| sel term term term term {
printf("<INPUT: SELECT %s %s %i %i>\n", $2, $3, $4, $5);
tup = get_pytup(ht_get(hashtable, $3), $4, $5, "py", "int", "int", 3);
ht_set(hashtable, $2, callpy("SELECT", tup));
ht_get( hashtable, $2 );
}
;
term : number {$$ = $1;}
| identifier {$$ = $1;}
;
%% /* C code */
/* Create a new hashtable. */
hashtable_t *ht_create(int size) {
hashtable_t *hashtable = NULL;
int i;
if(size < 1) return NULL;
/* Allocate the table itself. */
if((hashtable = malloc(sizeof( hashtable_t))) == NULL) {
return NULL;
}
/* Allocate pointers to the head nodes. */
if((hashtable->table = malloc(sizeof(entry_t *)*size)) == NULL) {
return NULL;
}
for( i = 0; i < size; i++ ) {
hashtable->table[i] = NULL;
}
hashtable->size = size;
return hashtable;
}
/* Hash a string for a particular hash table. */
int ht_hash(hashtable_t *hashtable, char *key) {
unsigned long int hashval;
int i = 0;
while( hashval < ULONG_MAX && i < strlen( key ) ) {
hashval = hashval << 8;
hashval += key[ i ];
i++;
}
return hashval % hashtable->size;
}
/* Create a key-value pair. */
entry_t *ht_newpair( char *key, PyObject *value ) {
entry_t *newpair;
if((newpair = malloc(sizeof(entry_t))) == NULL) {
return NULL;
}
if((newpair->key = strdup(key)) == NULL) {
return NULL;
}
if((newpair->value = value) == NULL) {
return NULL;
}
newpair->next = NULL;
return newpair;
}
/* Insert a key-value pair into a hash table. */
void ht_set( hashtable_t *hashtable, char *key, PyObject *value ) {
int bin = 0;
entry_t *newpair = NULL;
entry_t *next = NULL;
entry_t *last = NULL;
bin = ht_hash( hashtable, key );
next = hashtable->table[ bin ];
printf("SET Hash[%i]\n", bin);
while( next != NULL && next->key != NULL && strcmp(key, next->key)>0) {
last = next;
next = next->next;
}
/* There's already a pair. Let's replace that string. */
if( next != NULL && next->key != NULL && strcmp( key, next->key ) == 0 ) {
printf("Found a pair already on key: %s...\n", key);
next->value = value;
} else {
newpair = ht_newpair( key, value );
/* We're at the start of the linked list in this bin. */
if( next == hashtable->table[ bin ] ) {
newpair->next = next;
hashtable->table[ bin ] = newpair;
/* We're at the end of the linked list in this bin. */
} else if ( next == NULL ) {
last->next = newpair;
/* We're in the middle of the list. */
} else {
newpair->next = next;
last->next = newpair;
}
}
}
/* Retrieve a key-value pair from a hash table. */
PyObject *ht_get( hashtable_t *hashtable, char *key ) {
int bin = 0;
entry_t *pair;
bin = ht_hash( hashtable, key );
printf("GET Hash[%i] -> ", bin);
/* Step through the bin, looking for our value. */
pair = hashtable->table[ bin ];
while( pair != NULL && pair->key != NULL && strcmp( key, pair->key )>0) {
pair = pair->next;
}
if( pair == NULL || pair->key == NULL || strcmp( key, pair->key ) != 0 ) {
printf("ERROR: Found nothing from hashtable for key: %s\n", key);
return NULL;
} else {
printf("%s -> ", key);
PyObject_Print(pair->value, stdout, 0); printf("\n");
return pair->value;
}
}
PyObject* callpy(char* f_name, PyObject *tup) {
pFunc = PyDict_GetItemString(pDict, (char*)f_name);
presult = call_pyfunc();
printf("SUCCESS: Python Simulator Function Call\n");
return presult;
}
PyObject* get_pytup(void* a1, void* a2, void* a3, char* t1, char* t2, char* t3, int n_args) {
tup = PyTuple_New(n_args);
PyErr_Print();
if (a1 != " ") { set_tupitem(t1, a1, 0); }
if (a2 != " ") { set_tupitem(t2, a2, 1); }
if (a3 != " ") { set_tupitem(t3, a3, 2); }
return tup;
}
int set_tupitem(char* type, void* item, int pos) {
if (type == "py") {
PyTuple_SetItem(tup, pos, item);
} else if (type == "str") {
PyTuple_SetItem(tup, pos, PyDict_GetItemString(pDict, item));
} else if (type == "int") {
PyTuple_SetItem(tup, pos, Py_BuildValue("i", item));
} else {
printf("ERROR Setting item %s in pos %d..\n", item, pos);
return 0;
}
return 1;
PyErr_Print();
}
PyObject* call_pyfunc() {
if (PyCallable_Check(pFunc)) {
PyErr_Print();
presult = PyObject_CallObject(pFunc,tup);
}
PyErr_Print();
return presult;
}
int main (void) {
/* Set PYTHONPATH TO working directory */
setenv("PYTHONPATH",".",1);
/* Initialize the Python Interpreter */
Py_Initialize();
/* Prep Python */
pName = PyString_FromString((char*)"sim");
if(pName == NULL) {
PyErr_Print();
perror("PyString_FromString failed");
}
pModule = PyImport_Import(pName);
if(pModule == NULL) {
PyErr_Print();
perror("PyImport_Import failed");
}
pDict = PyModule_GetDict(pModule);
if(pDict == NULL) {
PyErr_Print();
perror("PyModule_GetDict failed");
}
printf("\nPARSER READY!\n");
/* Init hashtable for python objects */
hashtable = ht_create( 128 );
return yyparse ( );
}
void yyerror (const char *s) {
fprintf (stderr, "%s\n", s);
}

BIN
src/qasm

Binary file not shown.

0
src/sim.py → src/sim/sim.py

1892
src/y.tab.c

File diff suppressed because it is too large

97
src/y.tab.h

@ -1,97 +0,0 @@
/* A Bison parser, made by GNU Bison 3.0.4. */
/* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
#ifndef YY_YY_Y_TAB_H_INCLUDED
# define YY_YY_Y_TAB_H_INCLUDED
/* Debug traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
#if YYDEBUG
extern int yydebug;
#endif
/* Token type. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
enum yytokentype
{
print = 258,
exit_command = 259,
init = 260,
tensor = 261,
sel = 262,
measure = 263,
add = 264,
peek = 265,
gate = 266,
apply = 267,
number = 268,
identifier = 269
};
#endif
/* Tokens. */
#define print 258
#define exit_command 259
#define init 260
#define tensor 261
#define sel 262
#define measure 263
#define add 264
#define peek 265
#define gate 266
#define apply 267
#define number 268
#define identifier 269
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE
{
#line 48 "parser.y" /* yacc.c:1909 */
int num; char* id;
#line 85 "y.tab.h" /* yacc.c:1909 */
};
typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
extern YYSTYPE yylval;
int yyparse (void);
#endif /* !YY_YY_Y_TAB_H_INCLUDED */
Loading…
Cancel
Save