Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
victorlei committed Aug 26, 2016
1 parent 1cf07b9 commit c1f3320
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 70 deletions.
54 changes: 21 additions & 33 deletions smop/Makefile
Original file line number Diff line number Diff line change
@@ -1,59 +1,47 @@

# for py3: make PYTHON=python3 CYTHON="cython -3" V=3.4

VPATH = $(SCRIPTS)/strings $(SCRIPTS)/specfun
OCTAVE = /home/lei/octave-4.0.2
SCRIPTS = $(OCTAVE)/scripts

CYTHON = cython
PYTHON = python
XFILES = -x inputParser.m,quadgk.m,quadl.m,triplequad.m,dblquad.m,reallog.m,nthroot.m,factorial.m
FLAGS =
V = 2.7
ALL = \*.m
XFILES = -x inputParser

factorial.py: factorial.m
$(PYTHON) main.py -v $^ $(FLAGS)
all: mybench.py
$(PYTHON) -c "import mybench ; mybench.mybench()"
#m,uiputfile.m,uigetfile.m,qmr.m

#octave.py: primes.m interp2.m meshgrid.m repmat.m
# $(PYTHON) main.py --callgraph $(FLAGS) $^ -r core -o $@
# dot -Tpdf -o G.pdf G.dot
#quadgk.m,quadl.m,triplequad.m,dblquad.m
#installed_packages.m,stft.m,legend.m,__plt_get_axis_arg__.m,rotate.m,print.m,__ghostscript__.m,__gnuplot_print__.m,set.m,edit.m,what.m,usejava.m,javachk.m,__go_draw_axes__.m,interp3.m,interp2.m,interpn.m,randi.m,interp1.m,spdiags.m,importdata.m,stemleaf.m
FLAGS =
MYFLAGS=--ignore=999

#test_primes: octave.py
# $(PYTHON) -c "import octave ; octave.primes(1000)"
V = 2.7

octave.py:
find $(SCRIPTS)/general $(SCRIPTS)/specfun -name \*.m | xargs python main.py -o $@ $(FLAGS) $(XFILES)
all:
make -B FLAGS= liboctave.py | wc
make -B FLAGS=-C liboctave.py | wc
make -B FLAGS=-N liboctave.py | wc
make -B FLAGS=-T liboctave.py | wc
make -B FLAGS=-CN liboctave.py | wc
make -B FLAGS=-TN liboctave.py | wc
make -B FLAGS=-CT liboctave.py | wc
make -B FLAGS=-CTN liboctave.py | wc

liboctave.py:
find $(SCRIPTS) -name \*.m | xargs $(PYTHON) main.py -o $@ $(MYFLAGS) $(FLAGS) $(XFILES) $^
#$(PYTHON) $@

clean:
rm -f a.* *.pyc solver.so solver.py octave.so

solver.py: solver.m #r8_random.m octave.py
$(PYTHON) main.py $^ -o $@

check: solver.py
$(PYTHON) test_core.py
$(PYTHON) test_matlabarray.py
$(PYTHON) test_sparsearray.py
$(PYTHON) test_lexer.py
$(PYTHON) test_solver.py
# $(PYTHON) test_primes.py

#$(PYTHON) main.py $(FLAGS) -r core solver.m r8_random.m -o solver.py && python go.py
#test:
# find $(SCRIPTS) -name $(ALL) | xargs python main.py $(FLAGS)

regress:
make | sort -u | wc
%.c: %.py
$(CYTHON) $^

%.so: %.c
gcc -Wno-cpp -I /usr/include/python$V -O2 -shared -o $@ $^

%.py: %.m
#smop $(FLAGS) -o $@ $^
$(PYTHON) main.py -o $@ $^
$(PYTHON) $@

Expand Down
42 changes: 23 additions & 19 deletions smop/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"||": "or",
"&&": "and",
"^" : "**",
"**": "**",
".^": "**",
"./": "/",
".*": "*",
Expand Down Expand Up @@ -125,15 +126,18 @@ def _backend(self,level=0):

@extend(node.expr)
def _backend(self,level=0):
if self.op in ("!","not"): # ???
return "not %s" % self.args[0]._backend()
if self.op in ("&","and"):
if self.op in ("!","~"):
return "logical_not(%s)" % self.args[0]._backend()

if self.op == "&":
return "logical_and(%s)" % self.args._backend()

if self.op == "&&":
return "%s and %s" % (self.args[0]._backend(),
self.args[1]._backend())
if self.op in ("|","or"):
if self.op == "|":
return "logical_or(%s)" % self.args._backend()

if self.op == "||":
return "%s or %s" % (self.args[0]._backend(),
self.args[1]._backend())
Expand Down Expand Up @@ -216,17 +220,18 @@ def _backend(self,level=0):

@extend(node.func_stmt)
def _backend(self,level=0):
if len(self.args) == 1 and self.args[0].name == "varargin":
s = "\ndef %s(*args):" % self.ident._backend()
s += "\n varargin = cellarray(args)"
return s

if (self.args and
isinstance(self.args[-1],node.ident) and
self.args and
self.args[-1].name == "varargin"):
self.args[-1].name = "*varargin"
s = """
@function
def {0}({1}):
def %s(%s):
nargin = sys._getframe(1).f_locals["nargin"]
""".format(self.ident._backend(),
self.args._backend())
varargin = cellarray(varargin)
""" % (self.ident._backend(),
self.args._backend())

return s

Expand All @@ -251,7 +256,7 @@ def _backend(self,level=0):

@extend(node.ident)
def _backend(self,level=0):
return self.name if self.name not in reserved else self.name+'_'
return (self.name if self.name not in reserved else self.name+'_') + ("=" + self.init._backend() if self.init is not None else '')

@extend(node.if_stmt)
def _backend(self,level=0):
Expand Down Expand Up @@ -365,12 +370,11 @@ def _backend(self,level=0):

@extend(node.string)
def _backend(self,level=0):
# s = self.value.strip()
# if not s:
# return ""
# if s[0] in "%#":
# return "\n"+s.replace("%","#")
return '"%s"' % self.value.encode("string_escape").replace('"','\\"')
if "\n" in self.value:
fmt = '"""%s"""'
else:
fmt = '"%s"'
return fmt % self.value

@extend(node.sub)
def _backend(self,level=0):
Expand Down
20 changes: 14 additions & 6 deletions smop/lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class IllegalCharacterError(Exception):
"MINUS","MINUSMINUS","MINUSEQ","MUL","MULEQ","NE", "NEG",
"NUMBER", "OR","OREQ", "OROR", "PLUS", "PLUSEQ","PLUSPLUS",
"RBRACE", "RBRACKET", "RPAREN", "SEMI", "STRING",
"TRANSPOSE", "ERROR_STMT", "COMMENT", "END_FUNCTION", ]
"TRANSPOSE", "ERROR_STMT", "COMMENT", "END_FUNCTION","POW", ]

reserved = {
"break" : "BREAK",
Expand Down Expand Up @@ -73,6 +73,7 @@ def new():
t_MINUSEQ = r"\-="
t_MINUSMINUS = r"\--"
t_MUL = r"\*"
t_POW = r"\*\*"
t_MULEQ = r"\*="
t_NE = r"(~=)|(!=)"
t_NEG = r"\~|\!"
Expand All @@ -99,10 +100,16 @@ def unescape(s):
"""
ffd52d5fc5
"""
if s[0] == "'":
return s[1:-1].replace("''","'").decode("string_escape")
else:
return s[1:-1].replace('""','"').decode("string_escape")
try:
if s == r"'\'" or s == r'"\"':
return s[1:-1]
if s[0] == "'":
return s[1:-1].replace("''","'").decode("string_escape")
else:
return s[1:-1].replace('""','"').decode("string_escape")
except ValueError:
print s
raise

@TOKEN(mos)
def t_afterkeyword_STRING(t):
Expand Down Expand Up @@ -241,7 +248,8 @@ def t_NEWLINE(t):
return t

def t_ERROR_STMT(t):
r"%!error.*\n"
r"%!(error|warning|test).*\n"
t.lexer.lineno += 1

# keep multiline comments
def t_COMMENT(t):
Expand Down
27 changes: 19 additions & 8 deletions smop/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Copyright 2011-2016 Victor Leikehman
from os.path import splitext,basename
import version
import sys,cPickle,glob,os
import sys,cPickle,glob,os,tarfile
import getopt,re
import lexer
import parse
Expand All @@ -17,9 +17,14 @@
import graphviz

def main():
tar = None
if not options.filelist:
options.parser.print_help()
return
if (len(options.filelist) == 1 and
options.filelist[0].endswith(".tar")):
tar = tarfile.open(options.filelist[0])
options.filelist = tar.getnames()
if options.output == "-":
fp = sys.stdout
elif options.output:
Expand All @@ -39,29 +44,35 @@ def main():

for i, options.filename in enumerate(options.filelist):
try:
if not options.filename.endswith((".m",".tst")):
print "\tIgnored file: '%s' (unexpected file type)" % options.filename
if not options.filename.endswith((".m")):
if options.verbose:
print "\tIgnored: '%s' (unexpected file type)" % options.filename
continue
if os.path.basename(options.filename) in options.xfiles:
print "\tExcluded file: '%s'" % options.filename
print "\tExcluded: '%s'" % options.filename
continue
if options.verbose:
print options.filename
buf = open(options.filename).read().replace("\r\n","\n")
if tar:
buf = tar.extractfile(options.filename).read()
else:
buf = open(options.filename).read()
buf = buf.replace("\r\n","\n")
buf = buf.decode("ascii",errors="ignore")
stmt_list=parse.parse(buf if buf[-1]=='\n' else buf+'\n')
#assert None not in stmt_list
if not stmt_list and options.strict:
if not stmt_list:
return
if not options.no_resolve:
G = resolve.resolve(stmt_list)
if not options.no_backend:
s = backend.backend(stmt_list)
print >> fp, s
except Exception as e:
print e
if options.strict:
print "\tFailed: ",options.filename
if not options.ignore:
raise
options.ignore -= 1

if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion smop/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class number(atom,recordtype("number","value lineno lexpos",default=None)):
def __str__(self):
return str(self.value)

class ident(atom,recordtype("ident","name lineno column lexpos defs props",
class ident(atom,recordtype("ident","name lineno column lexpos defs props init",
default=None)):
def __str__(self):
return self.name
Expand Down
9 changes: 7 additions & 2 deletions smop/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
smop [options][file.m ...file.m][-l file.py...]
or
python -m smop.main [options][file.m ...file.m][-l file.py...]
smop [options] library.tar [-l file.py...]
""",
description= """
SMOP is Small Matlab and Octave to Python compiler.
Expand All @@ -19,7 +19,11 @@
compiled file unless explicitly set with -o . Additional
libraries can be specified with -l (lowercase L), for
example -loctave.py.""",
# epilog=
epilog="""Hint: put into your Makefile the following rule
%.py: %.m
$(SMOP) $^ $(FLAGS)
($(PYTHON) $@ && cat $@ >> libscripts.py)""",
formatter_class=argparse.RawTextHelpFormatter,
)

Expand Down Expand Up @@ -88,6 +92,7 @@
write Octave test suite. When disabled, behaves like
regular comments.""")

parser.add_argument("-I", "--ignore", type=int)


args = parser.parse_args(namespace=sys.modules[__name__])
Expand Down
17 changes: 16 additions & 1 deletion smop/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class syntax_error(error):
("left", "MUL","DIV","DOTMUL","DOTDIV","BACKSLASH"),
("right","UMINUS","NEG"),
("right","TRANSPOSE"),
("right","EXP", "DOTEXP"),
("right","EXP", "DOTEXP", "POW"),
("nonassoc","LPAREN","RPAREN","RBRACE","LBRACE"),
("left", "FIELD","DOT","PLUSPLUS","MINUSMINUS"),
)
Expand Down Expand Up @@ -137,16 +137,26 @@ def p_args_opt(p):
| LPAREN RPAREN
| LPAREN expr_list RPAREN
"""
flag = False
if len(p) == 1:
p[0] = node.expr_list()
elif len(p) == 3:
p[0] = node.expr_list()
elif len(p) == 4:
assert isinstance(p[2],node.expr_list)
p[0] = p[2]
flag = True
else:
assert 0

if flag:
t = p[2][-1]
if isinstance(t,node.ident) and t.name=="varargin":
t.name = "*varargin"
for t in p[2]:
if isinstance(t,node.ident) and t.name != '*varargin':
t.init = node.ident("None")


@exceptions
def p_break_stmt(p):
Expand Down Expand Up @@ -323,6 +333,7 @@ def p_expr2(p):
| expr DOTMUL expr
| expr DOTMULEQ expr
| expr EQEQ expr
| expr POW expr
| expr EXP expr
| expr EXPEQ expr
| expr GE expr
Expand Down Expand Up @@ -831,6 +842,10 @@ def p_while_stmt(p):

@exceptions
def p_error(p):
if p.type == "COMMENT":
#print "Discarded comment", p.value
parser.errok()
return
raise syntax_error(p)

parser = yacc.yacc(start="top")
Expand Down

0 comments on commit c1f3320

Please sign in to comment.