@@ -64,9 +64,20 @@ def get_output(self):
6464
6565class ParamStr (str ):
6666
67+ def __new__ (cls , s , args , n ):
68+ self = super ().__new__ (cls , s )
69+ self ._args = args
70+ self ._arg_idx = n
71+ return self
72+
6773 @property
6874 def escape (self ):
69- return '"%s"' % self .replace ('"' , '\\ "' )
75+ return ParamStr ('"%s"' % self .replace ('"' , '\\ "' ), self ._args ,
76+ self ._arg_idx )
77+
78+ @property
79+ def remainder (self ):
80+ return ParamStr (',' .join (self ._args [self ._arg_idx :]), [], 0 )
7081
7182class Preprocessor :
7283
@@ -119,6 +130,7 @@ def substitute(self, line):
119130 args = []
120131 s = ''
121132 end = start
133+ arg_num = 0
122134 for c in line [start :]:
123135 end += 1
124136 if c == '(' :
@@ -129,11 +141,12 @@ def substitute(self, line):
129141 break
130142 if brackets == 0 :
131143 if c == ',' :
132- args .append (s )
144+ args .append (ParamStr ( s , args , arg_num ) )
133145 s = ''
146+ arg_num += 1
134147 continue
135148 s += c
136- args .append (ParamStr (s ))
149+ args .append (ParamStr (s , args , arg_num ))
137150 line = line [:idx ] + replacement .format (* args ) + line [end :]
138151 # Recursively substitute
139152 line = self .substitute (line )
@@ -230,7 +243,7 @@ def handle_define(self, arg):
230243 if not self .block .output :
231244 return
232245 import re
233- match = re .match ('(\w+)\s*(\((?:\w+\s*,\s*)*(?:\w+)\s*\))?\s+(.+)' , arg )
246+ match = re .match ('(\w+)\s*(\((?:\w+\s*,\s*)*(?:(?: \w+|\.\.\.) )\s*\))?\s+(.+)' , arg )
234247 if not match :
235248 raise Exception ('invalid #define' )
236249 name = match .group (1 )
@@ -242,8 +255,16 @@ def handle_define(self, arg):
242255 else :
243256 params = self ._get_params (params )
244257 for i in range (len (params )):
245- replacement = re .sub (r'(\b|^)#%s(\b|$)' % params [i ], '{%d.escape}' % i , replacement )
246- replacement = re .sub (r'(\b|^)%s(\b|$)' % params [i ], '{%d}' % i , replacement )
258+ if params [i ] == '...' :
259+ replacement = replacement .replace ('#__VA_ARGS__' ,
260+ '{%d.remainder.escape}' % i )
261+ replacement = replacement .replace ('__VA_ARGS__' ,
262+ '{%d.remainder}' % i )
263+ continue
264+ replacement = re .sub (r'(\b|^)#%s(\b|$)' % params [i ],
265+ '{%d.escape}' % i , replacement )
266+ replacement = re .sub (r'(\b|^)%s(\b|$)' % params [i ],
267+ '{%d}' % i , replacement )
247268
248269 self .replacements [name ] = (idx , 'function' , replacement )
249270
@@ -521,6 +542,7 @@ def effective(type, ptr, is_array, array_size=None):
521542Indirect = namedtuple ('Indirect' , 'ref' )
522543Offset = namedtuple ('Offset' , 'ref offset' )
523544Direct = namedtuple ('Direct' , 'ref' )
545+ IndirectOffset = namedtuple ('IndirectOffset' , 'ref offset' )
524546
525547class CompilerVisitor (Visitor ):
526548
@@ -578,14 +600,14 @@ def visit_statements(self, stmts):
578600 self .visit_statement (stmt )
579601
580602 def visit_statement (self , stmt ):
581- self .clear_temporary_vars ()
582-
583603 if type (stmt ) == list :
584604 self .visit_statements (stmt )
585605 return
586606 elif isinstance (stmt , EmptyStatement ):
587607 return
588608
609+ self .clear_temporary_vars ()
610+
589611 stmt_map = {
590612 Declaration : self .visit_decl ,
591613
@@ -634,34 +656,42 @@ def visit_expression(self, expr):
634656 return func (expr )
635657
636658 def visit_func_decl (self , stmt ):
659+ self .define_function (stmt .type , stmt .decl , stmt .body )
660+
661+ def define_function (self , type_spec , def_spec , body = [], def_only = False ):
637662 # We must not be in a function here
638663 assert self .current_function is None
639- self .clear_locals ()
664+ if not def_only :
665+ self .clear_locals ()
640666
641- assert stmt . type .store is None
642- assert stmt . type .qual is None
667+ assert type_spec .store is None
668+ assert type_spec .qual is None
643669
644- ret_type = self .get_effective_type (stmt . type , stmt . decl )
670+ ret_type = self .get_effective_type (type_spec , def_spec )
645671
646- desc = stmt . decl .name_spec
672+ desc = def_spec .name_spec
647673 assert isinstance (desc , FuncDeclSpec )
648674
649675 name = desc .name .val
650- self .writer .write_subroutine (name )
676+ if not def_only :
677+ self .writer .write_subroutine (name )
651678
652679 param_types = []
653680 for param in desc .params :
654681 type = self .get_effective_type (param .type , param .decl )
655682 assert param .decl .name_spec is not None
656683 p_name = Types .get_name_for (param .decl .name_spec )
657684 param_types .append (type )
658- self .add_local (type , p_name )
685+ if not def_only :
686+ self .add_local (type , p_name )
659687
660688 func = Function (ret_type = ret_type , name = name , param_types = param_types )
661- self .current_function = func
662689 self .functions [name ] = func
663- self .visit_statements (stmt .body )
664- if not stmt .body or not isinstance (stmt .body [- 1 ], ReturnStmt ) \
690+ if def_only :
691+ return
692+ self .current_function = func
693+ self .visit_statements (body )
694+ if not body or not isinstance (body [- 1 ], ReturnStmt ) \
665695 and name != 'main' : # main function doesn't return
666696 self .write ('RET' )
667697 self .current_function = None
@@ -685,6 +715,10 @@ def visit_decl(self, decl):
685715 self .visit_type_def (decl )
686716 else :
687717 for init in decl .init :
718+ if isinstance (init .decl .name_spec , FuncDeclSpec ):
719+ assert init .val is None
720+ self .define_function (decl .type , init .decl , def_only = True )
721+ continue
688722 type_ = self .get_effective_type (decl .type , init .decl )
689723 name = Types .get_name_for (init .decl .name_spec )
690724 var = self .add_to_scope (type_ , name )
@@ -887,10 +921,18 @@ def unwrap(ref, tmp_reg_getter, tmp_reg=None):
887921 tmp_reg = tmp_reg_getter ()
888922 actions , b , o = unwrap (ref .ref , tmp_reg_getter , tmp_reg )
889923 return (actions + ((b , o , tmp_reg ),), tmp_reg , 0 )
924+ if isinstance (ref , IndirectOffset ):
925+ if not tmp_reg :
926+ tmp_reg = tmp_reg_getter ()
927+ actions , b , o = unwrap (ref .ref , tmp_reg_getter , tmp_reg )
928+ assert type (o ) == int , 'cannot indirectly reference this'
929+ return (actions + ((b , None , tmp_reg , ref .offset ),), tmp_reg , o )
890930 assert False , ref
891931
892932 def as_str (base , offset ):
893- return base if offset is None else '[%s%s]' % (base , '+0x%x' % offset if offset else '' )
933+ off = ('+0x%x' % offset if offset >= 0 else '-0x%x' % abs (offset )) \
934+ if offset is not None else ''
935+ return base if offset is None else '[%s%s]' % (base , off )
894936
895937 def move (src , src_off , dest , dest_off ):
896938 comment = '\t MOV %s, %s' % (as_str (src , src_off ), as_str (dest , dest_off ))
@@ -912,7 +954,12 @@ def act_out(steps):
912954 actions , base , offset = steps
913955 base = str (base ) # Convert any memory reference to string
914956 for action in actions :
915- a_base , a_off , a_dest = action
957+ a_base , a_off , a_dest , * extra = action
958+ if extra : # IndirectOffset
959+ assert type (a_base ) != int , 'unsupported array reference'
960+ move (a_base , None , a_dest , None )
961+ self .write ('ADD' , extra [0 ], a_dest )
962+ continue
916963 move (a_base , a_off , a_dest , None )
917964 return (base , offset )
918965
@@ -935,6 +982,9 @@ def move(self, src, dest):
935982 size = 1
936983 elif isinstance (src , Dereference ):
937984 size = 1
985+ elif isinstance (src .type , ArrayType ):
986+ # Just reference first offset in array
987+ size = src .type .type .size
938988 else :
939989 size = src .type .size
940990 src_addr = self .load_address (src )
@@ -973,9 +1023,12 @@ def load_address(self, ref):
9731023 if isinstance (ref , Global ):
9741024 return Direct (ref .loc )
9751025 if isinstance (ref , ArrayElement ):
976- return Offset (ref = self .load_address (ref .array ),
977- offset = ref .index * ref .type .type .size )
978- if isinstance (ref , (Relative , Direct , Offset , Indirect )):
1026+ a_ref = self .load_address (ref .array )
1027+ if type (ref .index ) == int :
1028+ return Offset (ref = a_ref , offset = ref .index * ref .type .size )
1029+ else :
1030+ return IndirectOffset (ref = a_ref , offset = ref .index )
1031+ if isinstance (ref , (Relative , Direct , Offset , Indirect , IndirectOffset )):
9791032 return ref
9801033 assert False , type (ref )
9811034
@@ -1334,7 +1387,12 @@ def visit_arr_subscript_expr(self, expr):
13341387 array = self .visit_expression (expr .expr )
13351388 index = self .visit_expression (expr .sub )
13361389 assert isinstance (array .type , ArrayType ), type (array .type )
1337- assert type (index ) == int , type (index ) # TODO non-constant index
1390+ if type (index ) != int :
1391+ tmp = self .new_temporary_var ()
1392+ with self .mutate (tmp , write_only = True ) as ref :
1393+ self .write ('MOV' , index , ref )
1394+ self .write ('MUL' , array .type .type .size , ref )
1395+ index = ref # unsafe expose of ref
13381396 return ArrayElement (array = array , index = index , type = array .type .type )
13391397
13401398 def visit_unary_expr (self , expr ):
@@ -1400,7 +1458,7 @@ def visit_func_call_expr(self, expr):
14001458 name = expr .ref .val
14011459 if name in self .optimized_functions :
14021460 return self .optimized_functions [name ](expr )
1403- assert name in self .functions
1461+ assert name in self .functions , "Unknown function %s" % name
14041462 func = self .functions [name ]
14051463 assert len (expr .args ) == len (func .param_types )
14061464 large_ret = func .ret_type .size > 1 # Can't fit in single register
@@ -1415,7 +1473,7 @@ def visit_func_call_expr(self, expr):
14151473 for arg in expr .args :
14161474 var = self .visit_expression (arg )
14171475 self .write ('MOV' , var , Relative (rel_to = 'cbp' , offset = i ))
1418- if type (var ) == int :
1476+ if type (var ) in [ int , str ] or isinstance ( var , Register ) :
14191477 i += 1
14201478 else :
14211479 i += var .type .size
0 commit comments