add bf functions, import statement and stdlib (and remove some opcodes). Also fix some bugs in op

This commit is contained in:
miggazElquez 2019-09-23 17:00:03 +02:00
parent 287a2a066a
commit 8bd8e3b458
6 changed files with 251 additions and 81 deletions

View File

@ -69,10 +69,6 @@ def interpret(prog):
return ar return ar
def format(prog,debug_mode=True):
if debug_mode:
return ''.join(i for i in prog if i in '[]<>+-.,#')
return ''.join(i for i in prog if i in '[]<>+-.,')
def repl(): def repl():

View File

@ -1,12 +1,13 @@
program = statement, {statement} program = statement, {statement}
block = "{",{statement}, "}" block = "{",{statement}, "}"
statement = short_statement | while_block | if_block | function_def statement = short_statement | while_block | if_block | function_def | function_bf
short_statement = print | return | input | declaration | assignement | expression | inc-dec, ";" short_statement = print | return | input | declaration | assignement | expression | inc-dec | import, ";"
assignement = name, assignement_symbol, expression assignement = name, assignement_symbol, expression
declaration = "var" , name , {",",name} declaration = "var" , name , {",",name}
return = "return", expression return = "return", expression
import = "import", string
expression = compar_op | function_call expression = compar_op | function_call
@ -14,9 +15,9 @@ function_call = name, '(',[expression,{','expression,}]
compar = calcul, [compar_op, calcul] compar = calcul, [compar_op, calcul]
calcul = terme, [('+'|'-'), terme] calcul = terme, {('+'|'-'), terme}
terme = factor [("*"|"/"), factor] terme = factor {("*"|"/"), factor}
factor = val ["**", val] factor = val {"**", val}
val = name | number | "(", expression, ")" val = name | number | "(", expression, ")"
inc-dec = name, ("++" | "--") inc-dec = name, ("++" | "--")
@ -24,9 +25,12 @@ condition = '(', expression, ')'
while_block = "while", condition, block while_block = "while", condition, block
if_block = "if", condition, block, ["else", block] if_block = "if", condition, block, ["else", block]
function_def = "def", name, '(',[name,{',',name}],')',block function_def = "def", name, '(',[name,{',',name}],')',block
function_bf = 'bf',name, '{', brainfuck_code, '}'
brainfuck_code = {'<'|'>'|'+'|'-'|'.'|','|'['|']'}
bin_op = "+"|"-"|"*"|"/"|"**" bin_op = "+"|"-"|"*"|"/"|"**"
compar_op = ">"|">="|"<"|"<="|"==" compar_op = ">"|">="|"<"|"<="|"=="
assignement_symbol = "="|"+="|"-="|"/="|"*=" assignement_symbol = "="|"+="|"-="|"/="|"*="

34
op.bf
View File

@ -11,6 +11,9 @@ COMPAR :
{add the last part} {add the last part}
Situation à la fin:
0 b 0 k
EQUALS : EQUALS :
+>[<->[-]]>>[<<<->>>-]<<< +>[<->[-]]>>[<<<->>>-]<<<
@ -18,16 +21,16 @@ DIFFERENT :
>[<+>[-]]>>[<<<+>>>-]<<< >[<+>[-]]>>[<<<+>>>-]<<<
GREATER : GREATER :
>>>[<<<+>>>-]<<< >[-]>>[<<<+>>>-]<<<
GREATER OR EQUALS : GREATER OR EQUALS :
+>[<->[-]]< +>[<->[-]]>>[-]<<<
SMALLER : SMALLER :
>[<+>[-]]< >[<+>[-]]>>[-]<<<
SMALLER OR EQUALS : SMALLER OR EQUALS :
+>>>[<<<->>>-]<<< +>[-]>>[<<<->>>-]<<<
@ -46,12 +49,31 @@ DIV :
[->+>>+<<<] [->+>>+<<<]
<[->+>>+<<<] <[->+>>+<<<]
>>> >>>
[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]+>[<->[-]]< [>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]+>[<->[-]]>>[-]<<<
[ [
-<[-<->>+<]>[-<+>] -<[-<->>+<]>[-<+>]
<<<+> <<<+>
[->>+>+<<<]>>>[-<<<+>>>]<< [->>+>+<<<]>>>[-<<<+>>>]<<
[->>+>+<<<]>>>[-<<<+>>>]< [->>+>+<<<]>>>[-<<<+>>>]<
<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]>>>[<<<+>>>-]<<< <[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]+>[<->[-]]>>[-]<<<
] ]
<[-]<[-]< <[-]<[-]<
MOD :
=====
[->+>>+<<<]
<[->+>>+<<<]
>>>
[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]+>[<->[-]]>>[-]<<<
[
-<[-<->>+<]>[-<+>]
<<
[->>+>+<<<]>>>[-<<<+>>>]<<
[->>+>+<<<]>>>[-<<<+>>>]<
<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]+>[<->[-]]>>[-]<<<
]
<[-]<[-<+>]<

33
stdlib.mg Normal file
View File

@ -0,0 +1,33 @@
/*
STDLIB
The comment after the bf function is the number of arguments
*/
bf putc {{ //1
.
}}
bf scanc {{ //0
>,
}}
bf debug {{ //0
#>
}}
def print_int(n){
var i, val;
i = 1;
while (i <= n){
i *= 10;
}
i /= 10;
while (i >= 1){
val = n / i;
n %= i;
putc(val + 48);
i /= 10;
}
return n;
}

48
stdlib.py Normal file
View File

@ -0,0 +1,48 @@
from collections import ChainMap
import to_bf_compiler as compiler
BUILT_IN_FUNCTIONS = ChainMap({})
BUILT_IN_FUNCTIONS['putc'] = [('PUTC',)]
BUILT_IN_FUNCTIONS['scanc'] =[('SCANC',)]
BUILT_IN_FUNCTIONS['debug'] = [('DEBUG',)]
func_to_compile = []
func_to_compile.append(
('print_int',"""
def print_int(n){
var i, val;
i = 1;
while (i <= n){
i *= 10;
}
i /= 10;
while (i >= 1){
val = n / i;
n %= i;
putc(val + 48);
i /= 10;
}
return n;
}
"""))
def compile_func(name,func):
ast = compiler.compile(func,2)
ir = compiler.Ast_to_IR(ast,BUILT_IN_FUNCTIONS) #on peut utiliser toutes les fonctions définis avant
ir.convert()
return ir.functions[name]
for name, func in func_to_compile:
BUILT_IN_FUNCTIONS[name] = compile_func(name,func)

View File

@ -9,18 +9,19 @@ os.system('color')
REGEXS = [(re.compile(i),j) for i,j in ( REGEXS = [(re.compile(i),j) for i,j in (
(r'\s+','WHITESPACE'), (r'\s+','WHITESPACE'),
(r'//[^\n]*|/\*(?s:.)*\*/','COMMENTS'), (r'//[^\n]*|/\*(?s:.)*\*/','COMMENTS'),
(r'if|for|while|else|var|def|return','KEYWORD'), (r'if|while|else|var|def|return|bf|import','KEYWORD'),
(r'\{\{[^}]*\}\}','BRAINFUCK_CODE'),
(r'>=|<=|==|>|<|!=','COMPAR_OP'), (r'>=|<=|==|>|<|!=','COMPAR_OP'),
(r'\+=|-=|\*=|/=|=','ASSIGNEMENT_OP'), (r'\+=|%=|-=|\*=|/=|=','ASSIGNEMENT_OP'),
(r'\+\+|--','INC_DEC_OP'), (r'\+\+|--','INC_DEC_OP'),
(r'\+|\*\*|\*|-|/','BIN_OP'), (r'\+|\*\*|\*|-|/|%','BIN_OP'),
(r'\(|\)|\{|\}|;|,','CONTROL_CHAR'), (r'\(|\)|\{|\}|;|,','CONTROL_CHAR'),
(r'[a-zA-Z]\w*','IDENTIFIERS'), (r'[a-zA-Z]\w*','IDENTIFIERS'),
(r'\d[\d_]*','NUMBERS'), (r'\d[\d_]*','NUMBERS'),
(r"'.'",'CHAR') (r"'.'",'CHAR'),
(r'"(\\.|[^"\n])*"','STRING'),
)] )]
USELESS_TAGS = ('WHITESPACE','COMMENTS') USELESS_TAGS = ('WHITESPACE','COMMENTS')
@ -47,6 +48,34 @@ def lex(program,keep_whitespace=False):
def clean_tokens(tokens): def clean_tokens(tokens):
return [token for token in tokens if token.tag not in USELESS_TAGS] return [token for token in tokens if token.tag not in USELESS_TAGS]
def format_bf(prog,debug_mode=True):
if debug_mode:
t = []
index = 0
while index < len(prog):
if prog[index] in '[]<>+-.,':
t.append(prog[index])
index += 1
elif prog[index] == '#':
t.append('#')
index += 1
try:
if prog[index] == '(':
index += 1
t.append('(')
while prog[index] != ')':
t.append(prog[index])
index+=1
t.append(')')
except IndexError:
pass
else:
index+=1
return ''.join(t)
return ''.join(i for i in prog if i in '[]<>+-.,')
#**************************** #****************************
@ -57,12 +86,14 @@ BlockNode = namedtuple('BlockNode',('list_of_statement'))
IfNode = namedtuple('IfNode',('condition','block','else_block')) IfNode = namedtuple('IfNode',('condition','block','else_block'))
WhileNode = namedtuple('WhileNode',('condition','block')) WhileNode = namedtuple('WhileNode',('condition','block'))
FunctionDefNode = namedtuple('FunctionDefNode',('name','args','block')) FunctionDefNode = namedtuple('FunctionDefNode',('name','args','block'))
BfDefNode = namedtuple('BfDefNode',('name','code'))
AssignementNode = namedtuple('AssignementNode',('target','operator','expression')) AssignementNode = namedtuple('AssignementNode',('target','operator','expression'))
IncDecNode = namedtuple('IncDecNode',('name','operator')) IncDecNode = namedtuple('IncDecNode',('name','operator'))
DeclarationNode = namedtuple('DeclarationNode',('names')) DeclarationNode = namedtuple('DeclarationNode',('names'))
FunctionCallNode = namedtuple('FunctionCallNode',('name','args')) FunctionCallNode = namedtuple('FunctionCallNode',('name','args'))
ReturnNode = namedtuple('ReturnNode',('expr')) ReturnNode = namedtuple('ReturnNode',('expr'))
ImportNode = namedtuple('ImportNode',('path',))
BinOpNode = namedtuple('BinOpNode',('left','op','right')) BinOpNode = namedtuple('BinOpNode',('left','op','right'))
IdentifierNode = namedtuple('IdentifierNode',('name')) IdentifierNode = namedtuple('IdentifierNode',('name'))
@ -105,6 +136,9 @@ class Parser:
nodes = [] nodes = []
while 1: while 1:
statement = self.statement() statement = self.statement()
if isinstance(statement,ImportNode):
ast = get_ast(statement.path)
nodes.extend(ast)
if statement: if statement:
nodes.append(statement) nodes.append(statement)
else: else:
@ -131,18 +165,15 @@ class Parser:
return BlockNode(nodes) return BlockNode(nodes)
def statement(self): def statement(self):
#print(f"enter statement ({self.pos})") for func in (self.short_statement,self.while_block, self.if_block,self.function_block, self.bf_block):
for func in (self.short_statement,self.while_block, self.if_block,self.function_block):
node = func() node = func()
if node: if node:
#cprint("statement",'green')
return node return node
#cprint("no statement",'red')
return None return None
def short_statement(self): def short_statement(self):
#print(f"enter short_statement ({self.pos})") #print(f"enter short_statement ({self.pos})")
for func in (self.declaration, self.assignement,self.inc_dec,self.expression,self.return_): for func in (self.declaration, self.assignement,self.inc_dec,self.expression,self.return_,self.import_):
node = func() node = func()
if node: if node:
if self.accept_text(";"): if self.accept_text(";"):
@ -153,6 +184,14 @@ class Parser:
#cprint("no short_statement",'red') #cprint("no short_statement",'red')
return None return None
def import_(self):
if not self.accept_text('import'):
return None
path = self.accept_tag('STRING')
if not path:
raise SyntaxError('Bad import')
return ImportNode(path.text[1:-1])
def return_(self): def return_(self):
if not self.accept_text('return'): if not self.accept_text('return'):
return None return None
@ -260,19 +299,22 @@ class Parser:
if not terme1: if not terme1:
return None return None
op = None while 1:
sym = self.accept_text('+') op = None
if sym: sym = self.accept_text('+')
op = sym if sym:
sym = self.accept_text('-') op = sym
if sym: sym = self.accept_text('-')
op = sym if sym:
op = sym
if not op:
return terme1
if op: if op:
terme2 = self.terme() terme2 = self.terme()
if not terme2: if not terme2:
raise SyntaxError("missing second term in calcul") raise SyntaxError("missing second term in calcul")
return BinOpNode(terme1,op.text,terme2) terme1 = BinOpNode(terme1,op.text,terme2)
return terme1 return terme1
@ -282,19 +324,25 @@ class Parser:
if not factor1: if not factor1:
return None return None
op = None while 1:
sym = self.accept_text('*') op = None
if sym: sym = self.accept_text('*')
op = sym if sym:
sym = self.accept_text('/') op = sym
if sym: sym = self.accept_text('/')
op = sym if sym:
op = sym
sym = self.accept_text('%')
if sym:
op = sym
if op: if op:
factor2 = self.factor() factor2 = self.factor()
if not factor2: if not factor2:
raise SyntaxError("missing second factor in terme") raise SyntaxError("missing second factor in terme")
return BinOpNode(factor1,op.text,factor2) factor1 = BinOpNode(factor1,op.text,factor2)
else:
break
return factor1 return factor1
def factor(self): def factor(self):
@ -302,12 +350,11 @@ class Parser:
val = self.value() val = self.value()
if not val: if not val:
return None return None
op = self.accept_text('**') while self.accept_text('**'):
if op: val2 = self.value()
val2 = self.value() if not val2:
if not val2: raise SyntaxError("missing second val un factor")
raise SyntaxError("missing second val un factor") val = BinOpNode(val,'**',val2)
return BinOpNode(val,op.text,val2)
return val return val
def value(self): def value(self):
@ -408,6 +455,19 @@ class Parser:
return FunctionDefNode(name.text,args,block) return FunctionDefNode(name.text,args,block)
def bf_block(self):
if not self.accept_text('bf'):
return None
name = self.accept_tag('IDENTIFIERS')
if not name:
raise SyntaxError("A bf function need a name")
code = self.accept_tag('BRAINFUCK_CODE')
if not code:
raise SyntaxError("Bad bf block")
code = format_bf(code.text[2:-2])
return BfDefNode(name.text,code)
@ -417,22 +477,23 @@ def parse(prog):
return parser.program() return parser.program()
def get_ast(path):
with open(path) as file:
code = file.read()
tokens = lex(code)
ast = Parser(tokens).parse()
return ast.list_of_statement
#*************** #***************
BUILT_IN_FUNCTIONS = ChainMap({
'putc':[('PUTC',)],
'scanc':[('SCANC',)],
'mod':[
('')
],
})
class Ast_to_IR: class Ast_to_IR:
def __init__(self,ast,functions=BUILT_IN_FUNCTIONS): def __init__(self,ast,functions=None):
if functions is None:
functions = ChainMap({})
self.ast = ast self.ast = ast
self.functions = functions self.functions = functions
@ -456,6 +517,9 @@ class Ast_to_IR:
for statement in statements: for statement in statements:
if isinstance(statement,FunctionDefNode): if isinstance(statement,FunctionDefNode):
self.functions[statement.name] = Ast_to_IR(statement,self.functions).convert() self.functions[statement.name] = Ast_to_IR(statement,self.functions).convert()
elif isinstance(statement,BfDefNode):
code = statement.code
self.functions[statement.name] = [('BF',code,statement.name)]
vars_ = [] vars_ = []
@ -573,6 +637,8 @@ methods = {
WhileNode: Ast_to_IR.while_to_ir, WhileNode: Ast_to_IR.while_to_ir,
IfNode: Ast_to_IR.if_to_ir, IfNode: Ast_to_IR.if_to_ir,
IncDecNode: Ast_to_IR.inc_dec_to_ir, IncDecNode: Ast_to_IR.inc_dec_to_ir,
BfDefNode: lambda self,node:None,
ImportNode: lambda self,node:None,
} }
default = Ast_to_IR.expression_statement_to_ir default = Ast_to_IR.expression_statement_to_ir
@ -587,6 +653,10 @@ def init_function(nb,name):
def end_function(nb,name): def end_function(nb,name):
return '<[-]' * nb + '>' * nb + (f"[-{'<'*nb}+{'>'*nb}]" if nb else "") + '<' * nb+ f' END_FUNCTION {name}' return '<[-]' * nb + '>' * nb + (f"[-{'<'*nb}+{'>'*nb}]" if nb else "") + '<' * nb+ f' END_FUNCTION {name}'
def bf(code,name):
return f"BF {name}\n{code}\nEND_BF"
def assign(val,name): def assign(val,name):
return f"{'<'*val}[-]{'>'*val}[-{'<'*val}+{'>'*val}]< ASSIGN {name}" return f"{'<'*val}[-]{'>'*val}[-{'<'*val}+{'>'*val}]< ASSIGN {name}"
@ -614,22 +684,25 @@ def bin_op(op):
elif op == '*': elif op == '*':
bf = "<[->>+<<]>[->[-<<+>>>+<]>[-<+>]<<]>[-]<<" bf = "<[->>+<<]>[->[-<<+>>>+<]>[-<+>]<<]>[-]<<"
elif op == '/': elif op == '/':
bf = "[->+>>+<<<]<[->+>>+<<<]>>>[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]+>[<->[-]]<" bf = ("[->+>>+<<<]<[->+>>+<<<]>>>[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]+>[<->[-]]>>[-]<<<"
"[-<[-<->>+<]>[-<+>]<<<+>[->>+>+<<<]>>>[-<<<+>>>]<<[->>+>+<<<]>>>[-<<<+>>>]<<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>" "[-<[-<->>+<]>[-<+>]<<<+>[->>+>+<<<]>>>[-<<<+>>>]<<[->>+>+<<<]>>>[-<<<+>>>]<<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>"
">[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]>>>[<<<+>>>-]<<<#]<[-]<[-]<" ">[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]+>[<->[-]]>>[-]<<<]<[-]<[-]<")
elif op == '%':
bf = "[->+>>+<<<]<[->+>>+<<<]>>>[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]+>[<->[-]]>>[-]<<<" \
"[-<[-<->>+<]>[-<+>]<<[->>+>+<<<]>>>[-<<<+>>>]<<[->>+>+<<<]>>>[-<<<+>>>]<<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>" \
"[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]+>[<->[-]]>>[-]<<<]<[-]<[-<+>]<"
elif op == '==': elif op == '==':
bf = "<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]" + "+>[<->[-]]>>[<<<->>>-]<<<" bf = "<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]" + "+>[<->[-]]>>[<<<->>>-]<<<"
elif op == '!=': elif op == '!=':
bf = "<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]" + ">[<+>[-]]>>[<<<+>>>-]<<<" bf = "<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]" + ">[<+>[-]]>>[<<<+>>>-]<<<"
elif op == '>': elif op == '>':
bf = "<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]" + ">>>[<<<+>>>-]<<<" bf = "<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]" + ">[-]>>[<<<+>>>-]<<<"
elif op == '>=': elif op == '>=':
bf = "<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]" + "+>[<->[-]]<" bf = "<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]" + "+>[<->[-]]>>[-]<<<"
elif op == '<': elif op == '<':
bf = "<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]" + ">[<+>[-]]<" bf = "<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]" + ">[<+>[-]]>>[-]<<<"
elif op == '<=': elif op == '<=':
bf = "<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]" + "+>>>[<<<->>>-]<<<" bf = "<[>[->+>+<<]>>[-<<+>>]+<[>-<[-]]>[->+>+<<]>>[-<<+>>]<[<<<<[-]+>+>>>-]<<<-<-]" + "+>[-]>>[<<<->>>-]<<<"
else: else:
raise Exception(f"bin_op {op} not implemented yet") raise Exception(f"bin_op {op} not implemented yet")
@ -654,12 +727,6 @@ def else_end():
def if_end(): def if_end():
return "<]>[-]<< IF_END" return "<]>[-]<< IF_END"
def putc():
return ". PRINT"
def scanc():
return ", INPUT"
def compile_ir(ir): def compile_ir(ir):
return '\n'.join(globals()[i[0].lower()](*i[1:]) for i in ir) return '\n'.join(globals()[i[0].lower()](*i[1:]) for i in ir)