====== C4 - generování instrukcí ======
===== Syntaktické predikáty =====
Gramatika využívá syntaktické predikáty
[[http://gitlab.fjfi.cvut.cz/culikzde/view/-/blob/master/tutorial/cecko4.g|cecko4.g]]
[ predicate ] => grammar_expression
Pokud nalezneme dva identifikátory následované **=** nebo **;** zpracujeme deklaraci
stat < select CmmStat > :
[ identifier identifier ( '=' | ';' ) ] => decl_stat |
while_stat |
if_stat |
for_stat |
return_stat |
compound_stat |
simple_stat |
empty_stat ;
def parse_stat (self) :
if self.token == self.identifier and self.test_1 () :
result = self.parse_decl_stat ()
elif self.tokenText == "while" :
result = self.parse_while_stat ()
...
Vygenerovaná funkce **test_1** si uloží pozici ve vstupním testu (**mark**). \\
Otestuje přítomnost identifikátorů následovaných **=** nebo **;**. \\
Vrátí se na původní místo v zdrojovém textu (**rewind**). \\
Jako výsledek vrátí boolean.
def test_1 (self) :
result = True
position = self.mark ()
if result and self.token != self.identifier :
result = False
if result :
self.nextToken ()
if result and self.token != self.identifier :
result = False
if result :
self.nextToken ()
if self.tokenText == "=" :
if result :
self.nextToken ()
elif self.tokenText == ";" :
if result :
self.nextToken ()
else :
result = False
self.rewind (position)
return result
===== Generování instrukcí =====
Pokus o generování instrukcí pro EV3
{{prekl::c4_instr.png?800}}
===== Program generující instrukce =====
[[http://gitlab.fjfi.cvut.cz/culikzde/view/-/blob/master/tutorial/cecko4_instr.py|cecko4_instr.py]]
# cecko4_instr.py
from __future__ import print_function
from input import indexToFileName
from lexer import LexerException
from cecko4_parser import *
from output import Output
from bytecodes_instr import *
from bytecodes_par import *
from encode import *
# from cmdlib import *
# --------------------------------------------------------------------------
class Answer (object) :
def __init__ (self) :
self.name = ""
self.type = ""
self.size = 0
self.real = False
self.local = False
self.const = False
self.label = False
self.position = 0
self.register = False
# --------------------------------------------------------------------------
class Jump (object) :
def __init__ (self) :
self.source = 0
self.target = 0
self.size = 4
self.location = None
# --------------------------------------------------------------------------
class Instructions (Output) :
def __init__ (self) :
super (Instructions, self).__init__ ()
self.instr_table = { }
for oc in OpCodes :
self.instr_table [oc.cmd_txt] = oc
self.module = None
self.objects = [ ]
self.lab_cnt = 0
self.label_dict = { }
self.jump_list = [ ]
self.code = bytearray ([ ])
self.show_hex = True
self.short_jumps = True
# self.short_jumps = False
self.report_fileInx = 0
self.report_lineNum = 0
self.report_colNum = 0
def error (self, text) :
raise IOError (indexToFileName (self.report_fileInx) + ":" +
str (self.report_lineNum) + ":" +
str (self.report_colNum) + ":" +
" error: " + text )
def updatePosition (self, item) :
"set position for error reporting"
self.report_fileInx = item.src_file
self.report_lineNum = item.src_line
self.report_colNum = item.src_column
self.report_byteOfs = item.src_pos
# text manipulation
def location (self) :
cursor = self.sections.cursor
return (cursor.blockNumber (), cursor.columnNumber ())
def goto (self, loc) :
cursor = self.sections.cursor
cursor.movePosition (cursor.Start)
cursor.movePosition (cursor.NextBlock, cursor.MoveAnchor, loc [0])
cursor.movePosition (cursor.NextCharacter, cursor.MoveAnchor, loc [1])
def goto_end (self) :
cursor = self.sections.cursor
cursor.movePosition (cursor.End)
def remove (self, cnt) :
cursor = self.sections.cursor
for k in range (cnt) :
cursor.deleteChar ()
def add_lines (self, cnt) :
for i in range (cnt) :
self.putEol ()
def remove_lines (self, cnt) :
if cnt > 0 :
self.remove (cnt-1)
# instructions
def alloc_lab (self) :
self.lab_cnt = self.lab_cnt + 1
return "label_" + str (self.lab_cnt)
def place_lab (self, label) :
self.setInk ("orange")
self.put (label)
self.setInk (None)
self.put (" :")
self.putEol ()
if not label.startswith ("label_") :
self.error ("Invalid label name: " + label)
inx = int (label [6:])
self.label_dict [inx] = len (self.code)
def update_labels (self) :
for jump in self.jump_list :
target = self.label_dict [jump.target]
source = jump.source
if jump.size == 2 :
value = target-source-3
if value < DATA8_MIN or value > DATA8_MAX :
self.error ("Relative jump too long")
sequence = LC2 (value)
self.code [source:source+3] = sequence # 3 bytes
if jump.size == 4 :
value = target-source-5
sequence = LC4 (value)
self.code [source:source+5] = sequence # 5 bytes
# print ("at ", source, "place", value)
if self.show_hex :
loc = self.location ()
self.goto (jump.location)
self.remove (3 * len(sequence))
self.setInk ("red")
for n in sequence :
self.put (format (n, "02x"))
self.put (" ")
self.goto (loc)
# clear data for next procedure
self.label_dict = { }
self.jump_list = [ ]
def put_item (self, item) :
if item.label :
if self.short_jumps :
params = LC2 (0)
else :
params = LC4 (0)
inx = item.position
jump = Jump ()
jump.source = len (self.code)
jump.target = inx
jump.size = len (params) - 1
jump.location = self.location ()
self.jump_list.append (jump)
elif item.const :
params = LC (int (item.position))
elif item.local :
params = LV (int (item.position))
else :
params = GV (int (item.position))
self.code += params
if self.show_hex :
for n in params :
self.put (format (n, "02x"))
self.put (" ")
def put_item_text (self, item) :
if item.label :
inx = item.position
self.setInk ("orange")
self.put ("label_" + str (inx))
self.setInk (None)
elif item.const :
self.setInk ("cornflowerblue")
self.put ("LC(")
self.put (str (item.position))
self.put (")")
self.setInk (None)
elif item.local :
self.setInk ("lime")
self.put ("LV(")
self.put (str (item.position))
self.put (")")
self.setInk (None)
else :
self.setInk ("green")
self.put ("GV(")
self.put (str (item.position))
self.put (")")
self.setInk (None)
if item.name != "" :
self.setInk ("gray")
self.put ("/*" + item.name + "*/")
self.setInk (None)
def put_instr (self, name, items) :
if name not in self.instr_table :
self.error ("Invalid instruction name: " + name)
oc = self.instr_table [name]
cmd = oc.cmd
if self.show_hex :
self.setInk ("gray")
pos = len (self.code)
self.put (format (pos, "04x"))
self.put (" ")
self.setInk ("peru")
self.code.append (cmd)
self.put (format (cmd, "02x"))
self.put (" ")
for item in items :
self.put_item (item)
self.setInk ("blue")
self.put (name)
self.setInk (None)
first = True
for item in items :
if first :
first = False
else :
self.put (",")
self.put (" ")
self.put_item_text (item)
self.putEol ()
def put_stat (self, name) :
self.setInk ("gray")
self.putLn ("/* " + name + " */")
self.setInk (None)
def put_note (self, text) :
self.setInk ("plum")
self.putLn ("/* " + text + " */")
self.setInk (None)
def put_bytes (self, text, code) :
self.setInk ("red")
self.put (text + ": ")
self.setInk ("peru")
for c in code :
self.put (format (c, "02x"))
self.put (" ")
self.putEol ()
self.setInk (None)
# -----------------------------------------------------------------------
def alloc_reg (self, size) :
scope = self.display [-1]
answer = Answer ()
answer.size = size
answer.real = False
answer.const = False
answer.local = True
answer.position = scope.used_bytes
scope.used_bytes = scope.used_bytes + size
if scope.used_bytes > scope.local_bytes :
scope.local_bytes = scope.used_bytes
answer.register = True
self.setInk ("mediumpurple")
self.putLn ("/* register LV(" + str (answer.position) + ") */")
# ", used_bytes = " + str (scope.used_bytes) + ", local_bytes = " + str (scope.local_bytes)
self.setInk (None)
return answer
def remember_reg (self) :
scope = self.display [-1]
scope.reg_list.append (scope.used_bytes)
pass
def free_reg (self) :
scope = self.display [-1]
used = scope.reg_list [-1]
scope.used_bytes = used
scope.reg_list.pop ()
pass
def describe_var (self, var) :
answer = Answer ()
answer.name = getattr (var, "name", "")
answer.size = var.size
answer.real = False
answer.const = False
answer.local = not var.global_variable
answer.position = var.position
answer.register = False
return answer
def describe_const (self, value) :
answer = Answer ()
answer.size = 4
answer.real = False
answer.const = True
answer.local = False
answer.position = value
answer.register = False
return answer
def lookup (self, name) :
result = None
inx = len (self.display) - 1
while result == None and inx >= 0 :
result = self.display [inx].item_dict.get (name)
inx = inx - 1
return result
def code_instr (self, name, *args) :
# print ("args", args)
items = [ ]
inx = 0
for item in args :
if isinstance (item, int) :
value = item
item = Answer ()
item.const = True
item.position = value
elif isinstance (item, str) and item.startswith ("label_") :
num = int (item [6:])
item = Answer ()
item.label = True
item.position = num
if not isinstance (item, Answer) :
self.error ("Invalid parameter type")
# print ("item", item)
items.append (item)
inx = inx + 1
# print ("items", items)
self.put_instr (name, items)
def code_jump (self, name, *args) :
self.code_instr (name, *args)
# -----------------------------------------------------------------------
def code_builtin (self, name, expr_list) :
oc = self.instr_table [name]
detail = None
args = [ ]
inx = 0
sub_inx = 0
for expr in expr_list :
if detail == None :
par = oc.params [inx]
if par == PAR8 and oc.params [inx+1] == SUBP :
sub_key = oc.params [inx+2]
inx = inx + 2
if isinstance (expr, CmmVarExpr) :
sub_name = expr.name
for sc in SubCodes :
if sc.cmd_key == sub_key and sc.sub_code_txt == sub_name :
detail = sc
args.append (detail.sub_code)
elif par == PAR8 or par == PAR16 or par == PAR32 :
answer = self.code_expr (expr)
args.append (answer)
inx = inx + 1
else :
par = detail.sub_params [sub_inx]
if par == PAR8 or par == PAR16 or par == PAR32 :
answer = self.code_expr (expr)
args.append (answer)
sub_inx = sub_inx + 1
self.code_instr (name, *args)
# -----------------------------------------------------------------------
def code_cond (self, expr, direction, label) :
self.updatePosition (expr)
self.openSection (expr)
done = False
if expr.kind == expr.subexprExp :
self.code_cond (expr.inner_expr, direction, label) # expression inside parenthesis
done = True
elif expr.kind == expr.logNotExp :
self.put_note ("not, direction=" + str (direction))
self.code_cond (expr.param, not direction, label)
done = True
elif expr.kind == expr.logAndExp :
self.put_note ("and, direction=" + str (direction))
if direction == True :
temp_lab = self.alloc_lab ()
self.code_cond (expr.left, False, temp_lab)
self.code_cond (expr.right, True, label)
self.place_lab (temp_lab)
else :
self.code_cond (expr.left, False, label)
self.code_cond (expr.right, False, label)
done = True
elif expr.kind == expr.logOrExp :
self.put_note ("or, direction=" + str (direction))
if direction == True :
self.code_cond (expr.left, True, label)
self.code_cond (expr.right, True, label)
else :
temp_lab = self.alloc_lab ()
self.code_cond (expr.left, True, temp_lab)
self.code_cond (expr.right, False, label)
self.place_lab (temp_lab)
done = True
elif isinstance (expr, CmmRelExpr) or isinstance (expr, CmmEqExpr) :
left = self.code_expr (expr.left)
right = self.code_expr (expr.right)
instr = ""
if direction :
if expr.kind == expr.eqExp :
instr = "JR_EQ32"
elif expr.kind == expr.neExp :
instr = "JR_NE32"
elif expr.kind == expr.ltExp :
instr = "JR_LT32"
elif expr.kind == expr.gtExp :
instr = "JR_GT32"
elif expr.kind == expr.leExp :
instr = "JR_LTEQ32"
elif expr.kind == expr.geExp :
instr = "JR_GTEQ32"
else :
if expr.kind == expr.eqExp :
instr = "JR_NE32"
elif expr.kind == expr.neExp :
instr = "JR_EQ32"
elif expr.kind == expr.ltExp :
instr = "JR_GTEQ32"
elif expr.kind == expr.gtExp :
instr = "JR_LTEQ32"
elif expr.kind == expr.leExp :
instr = "JR_GT32"
elif expr.kind == expr.geExp :
instr = "JR_LT32"
if instr != "" :
self.put_note ("compare, direction=" + str (direction))
self.code_jump (instr, left, right, label)
done = True
if not done :
self.put_note ("expression, direction=" + str (direction))
answer = self.code_expr (expr)
if direction :
self.code_jump ("JR_TRUE", answer, label)
else :
self.code_jump ("JR_FALSE", answer, label)
self.closeSection ()
def code_arit (self, name, left, right) :
if left.register :
answer = left
elif right.register :
answer = right
else :
answer = self.alloc_reg (left.size)
self.code_instr (name, left, right, answer)
return answer
def code_expr (self, expr) :
self.updatePosition (expr)
answer = None
done = False
self.openSection (expr)
if expr.kind == expr.varExp :
name = expr.name
# self.put_note ("variable " + name)
var = self.lookup (name) # !?
if var == None :
self.error ("Unknown variable: " + name)
answer = self.describe_var (var)
elif expr.kind == expr.intValueExp :
# self.put_note ("integer constant " + str (expr.value))
answer = self.describe_const (expr.value)
elif expr.kind == expr.subexprExp :
answer = self.code_expr (expr.inner_expr)
elif expr.kind == expr.assignExp :
right = self.code_expr (expr.right)
left = self.code_expr (expr.left)
self.code_instr ("MOVE32_32", right, left)
done = True
elif expr.kind == expr.callExp :
if expr.left.kind == expr.varExp :
name = expr.left.name
if name in self.instr_table :
self.code_builtin (name, expr.param_list.items)
done = True
else :
parameters = [ ]
for param in expr.param_list.items :
value = self.code_expr (param)
parameters.append (value)
function = self.describe_const (2) # !? first procedure
count = self.describe_const (len (parameters))
self.code_instr ("CALL", function, count, *parameters)
done = True
elif expr.kind == expr.incExp or expr.kind == expr.decExp :
left = self.code_expr (expr.param)
one = self.describe_const (1)
instr = ""
if expr.kind == expr.incExp :
instr = "ADD32"
elif expr.kind == expr.decExp :
instr = "SUB32"
self.code_instr (instr, left, one, left)
answer = left
done = True
elif expr.kind == expr.postIncExp or expr.kind == expr.postDecExp :
left = self.code_expr (expr.left)
one = self.describe_const (1)
answer = self.alloc_reg (left.size)
self.code_instr ("MOVE32_32", left, answer)
instr = ""
if expr.kind == expr.postIncExp :
instr = "ADD32"
elif expr.kind == expr.postDecExp :
instr = "SUB32"
self.code_instr (instr, left, one, left)
elif isinstance (expr, CmmMulExpr) :
left = self.code_expr (expr.left)
right = self.code_expr (expr.right)
instr = "??"
if expr.kind == expr.mulExp :
instr = "MUL32"
elif expr.kind == expr.divExp :
instr = "DIV32"
answer = self.code_arit (instr, left, right)
elif isinstance (expr, CmmAddExpr) :
left = self.code_expr (expr.left)
right = self.code_expr (expr.right)
instr = ""
if expr.kind == expr.addExp :
instr = "ADD32"
elif expr.kind == expr.subExp :
instr = "SUB32"
answer = self.code_arit (instr, left, right)
elif expr.kind == expr.logAndExp :
answer = self.code_cond (left, right)
elif expr.kind == expr.logOrExp :
answer = self.code_cond (left, right)
elif isinstance (expr, CmmRelExpr) or isinstance (expr, CmmEqExpr) :
left = self.code_expr (expr.left)
right = self.code_expr (expr.right)
instr = ""
if expr.kind == expr.eqExp :
instr = "CP_EQ32"
elif expr.kind == expr.neExp :
instr = "CP_NE32"
elif expr.kind == expr.ltExp :
instr = "CP_LT32"
elif expr.kind == expr.gtExp :
instr = "CP_GT32"
elif expr.kind == expr.leExp :
instr = "CP_LTEQ32"
elif expr.kind == expr.geExp :
instr = "CP_GTEQ32"
answer = self.code_arit (instr, left, right)
if answer == None and not done:
self.error ("Not implemented")
if answer == None :
answer = Answer ()
answer.name = "unknown"
self.closeSection ()
return answer
# -----------------------------------------------------------------------
def code_stat (self, stat) :
self.updatePosition (stat)
self.openSection (stat)
if isinstance (stat, CmmSimpleStat) :
self.put_stat ("simple statement")
expr = stat.inner_expr
self.remember_reg ()
self.code_expr (expr)
self.free_reg ()
elif isinstance (stat, CmmIfStat) :
self.put_stat ("if")
lab_else = self.alloc_lab ()
self.code_cond (stat.cond, False, lab_else)
self.incIndent ()
self.code_stat (stat.then_stat)
self.decIndent ()
if stat.else_stat == None :
self.place_lab (lab_else)
else :
lab_end = self.alloc_lab ()
self.code_jump ("JR", lab_end)
self.put_stat ("else")
self.incIndent ()
self.place_lab (lab_else)
self.code_stat (stat.else_stat)
self.place_lab (lab_end)
self.decIndent ()
elif isinstance (stat, CmmForStat) :
self.put_stat ("for")
lab_begin = self.alloc_lab ()
lab_end = self.alloc_lab ()
# initialize loop variable
if stat.from_expr != None :
self.code_expr (stat.from_expr)
# begin of loop
self.place_lab (lab_begin)
# compare
if stat.cond_expr != None :
self.code_cond (stat.cond_expr, False, lab_end)
# inner statement
self.incIndent ()
self.code_stat (stat.body_stat)
self.decIndent ()
# increment or decrement
self.put_stat ("end of for")
if stat.step_expr != None :
self.code_expr (stat.step_expr)
# end of loop
self.code_jump ("JR", lab_begin)
self.place_lab (lab_end)
elif isinstance (stat, CmmWhileStat) :
self.put_stat ("while")
lab_begin = self.alloc_lab ()
self.place_lab (lab_begin)
lab_end = self.alloc_lab ()
self.code_cond (stat.cond, False, lab_end)
self.incIndent ()
self.code_stat (stat.body_stat)
self.decIndent ()
self.put_stat ("end of while")
self.code_jump ("JR", lab_begin)
self.place_lab (lab_end)
elif isinstance (stat, CmmCompoundStat) :
self.put_stat ("{")
self.incIndent ()
for item in stat.items :
self.code_stat (item)
self.decIndent ()
self.put_stat ("}")
elif isinstance (stat, CmmDeclStat) :
self.code_local_declaration (stat)
else :
self.error ("Statement not implemented")
self.closeSection ()
# -----------------------------------------------------------------------
def code_alloc (self, decl, scope, global_alloc) :
size = 0
if decl.type == "int" :
size = 4
if decl.type == "short" :
size = 2
if decl.type == "char" or decl.type == "bool" :
size = 1
if decl.type == "float" :
size = 4
if decl.type == "string" :
size = 4
if size == 0:
self.error ("Type not implemented")
if size != 0 :
align = size
if align > 4 :
align = 4
if global_alloc :
pos = scope.global_bytes
else :
pos = scope.local_bytes
rem = pos % align
if rem != 0 :
pos = pos + align - rem
decl.size = size
decl.global_variable = global_alloc
decl.position = pos
if global_alloc :
scope.global_bytes = pos + size
else :
scope.used_bytes = pos + size
scope.local_bytes = pos + size
self.put (", " + str (decl.size) + " bytes")
self.put (", position " + str (decl.position))
def code_variable (self, decl, scope, global_alloc) :
self.updatePosition (decl)
self.setInk ("green")
self.put ("var " + decl.name)
self.code_alloc (decl, scope, global_alloc)
self.setInk ("None")
self.putLn ()
def code_local_declaration (self, decl) :
scope = self.display [-1] # local scope
self.code_variable (decl, scope, global_alloc = False)
def code_global_variable (self, decl) :
scope = self.display [0] # global scope
self.code_variable (decl, scope, global_alloc = True)
# -----------------------------------------------------------------------
def code_param_list (self, parameters, scope) :
for decl in parameters.items :
self.setInk ("red")
self.put ("param " + decl.name)
self.code_alloc (decl, scope, global_alloc = False)
self.setInk ("None")
self.putLn ()
def code_function (self, proc, is_main = False) :
self.updatePosition (proc)
self.openSection (proc)
self.setInk ("orange")
self.put ("proc ")
self.setInk ("cornflowerblue")
self.addDefinition (proc.name, "function " + proc.name)
self.setInk (None)
self.putEol ()
self.incIndent ()
proc.used_bytes = 0
proc.local_bytes = 0
proc.reg_list = [ ]
self.code = bytearray ([ ])
proc.subroutine_cursor = self.location ()
if is_main :
self.add_lines (3)
else :
self.add_lines (4)
self.display.append (proc)
if not is_main :
self.code_param_list (proc.param_list, proc)
for stat in proc.body.items :
self.code_stat (stat)
if not is_main :
self.code_instr ("RETURN")
self.code_instr ("OBJECT_END")
self.decIndent ()
self.putLn ()
self.display.pop ()
self.closeSection ()
self.update_labels ()
proc.code = self.code # store generated code
if is_main :
self.main_code = proc.code
if not is_main :
self.objects.append (proc) # store object
self.code = bytearray ([ ])
# -----------------------------------------------------------------------
def code_declarations (self, declarations) :
self.main_func = None
for decl in declarations.items :
if decl.body == None :
self.code_global_variable (decl)
else :
is_main = (decl.name == "main")
self.code_function (decl, is_main)
if is_main :
self.main_func = decl
if self.main_func == None :
self.error ("Missing main function")
# -----------------------------------------------------------------------
def code_program (self, module) :
# module ... declaration list
self.openSection (module)
self.module_cursor = self.location ()
self.add_lines (5)
module.global_bytes = 0
# module.used_bytes = 0
# module.local_bytes = 0
# module.reg_list = [ ]
self.display = [module]
self.code_declarations (module)
self.display.pop ()
self.closeSection ()
# program header
version = 0
self.program = PROGRAMHeader (version, 1 + len (self.objects), module.global_bytes)
pos = len (self.program) + 12 + 12 * len (self.objects) # position for first instruction
# main function header
header = VMTHREADHeader (pos, self.main_func.local_bytes)
self.program += header
module.first_instr = pos
pos += len (self.main_func.code)
self.goto (self.main_func.subroutine_cursor)
self.remove_lines (3)
self.put_bytes ("offset to instruction", header [0:4])
self.put_bytes ("object id / trigger count", header [4:8])
self.put_bytes ("local bytes", header [8:12])
self.goto_end ()
# function headers
for obj in self.objects :
parameters = bytearray ([ ])
cnt = 0
for decl in obj.param_list.items :
parameters.append (IN_32)
cnt = cnt + 1
parameters = ByteToBytes (cnt) + parameters
obj.code = parameters + obj.code
header = SUBCALLHeader (pos, obj.local_bytes)
self.program += header
obj.first_instr = pos
pos += len (obj.code)
self.goto (obj.subroutine_cursor)
self.remove_lines (4)
self.put_bytes ("offset to instruction", header [0:4])
self.put_bytes ("object id / trigger count", header [4:8])
self.put_bytes ("local bytes", header [8:12])
self.put_bytes ("parameters", parameters)
self.goto_end ()
# main function instructions
if len (self.program) != module.first_instr :
self.error ("Bad position of main fuction")
self.program += self.main_func.code
# procedure instructions
for obj in self.objects :
if len (self.program) != obj.first_instr :
self.error ("Bad procedure position")
self.program += obj.code
if len (self.program) != pos :
self.error ("Bad program size")
# update program size
self.program [4:8] = LongToBytes (len (self.program))
self.goto (self.module_cursor)
self.remove_lines (5)
self.put_bytes ("header", self.program [0:4])
self.put_bytes ("program size", self.program [4:8])
self.put_bytes ("bytecode version", self.program [8:10])
self.put_bytes ("number of objects", self.program [10:12])
self.put_bytes ("global bytes", self.program [12:16])
self.goto_end ()
# print Program
self.setInk ("peru")
n = 0
for c in self.program :
self.put (format (c, "02x") + " ")
print (format (c, "02x"), end=" ")
n = n + 1
if n % 16 == 0 :
self.putLn ()
print ()
elif n % 4 == 0 :
self.put ("| ")
print ("|", end=" ")
self.putEol ()
self.setInk (None)
print ()
prog_list = self.program
if 0 :
connectToEV3 ()
print ("battery info:", batteryInfo ())
deleteFile ("../prjs/test/test.rbf")
writeFile ("../prjs/test/test.rbf", prog_list)
listFiles ("../prjs/test")
runFile ("../prjs/test/test.rbf")
print ("======")
time.sleep (5)
print ("======")
# stopProgram ()
Off (15)