11from collections import defaultdict
2+ from bisect import bisect_left , bisect_right
23from typing import Dict , List , Optional , Tuple
34
45from src .api import global_ as gl
@@ -16,6 +17,8 @@ class Memory:
1617 """ A class to describe memory
1718 """
1819 MAX_MEM = 65535 # Max memory limit
20+ _tmp_labels : Dict [int , Dict [str , Label ]]
21+ _tmp_labels_lines : List [int ]
1922
2023 def __init__ (self , org : int = 0 ):
2124 """ Initializes the origin of code.
@@ -24,10 +27,9 @@ def __init__(self, org: int = 0):
2427 self .memory_bytes : Dict [int , int ] = {} # An array (associative) containing memory bytes
2528 self .local_labels : List [Dict [str , Label ]] = [{}] # Local labels in the current memory scope
2629 self .global_labels = self .local_labels [0 ] # Global memory labels
27- self .tmp_labels : Dict [int , Dict [str , Label ]] = defaultdict (dict )
28- self .tmp_labels_lines : List [int ] = []
2930 self .ORG = org # last ORG value set
3031 self .scopes : List [int ] = []
32+ self .clear_temporary_labels ()
3133
3234 # Origins of code for asm mnemonics.
3335 # This will store corresponding asm instructions
@@ -38,6 +40,7 @@ def enter_proc(self, lineno: int):
3840 """
3941 self .local_labels .append ({}) # Add a new context
4042 self .scopes .append (lineno )
43+ self .clear_temporary_labels ()
4144 __DEBUG__ ('Entering scope level %i at line %i' % (len (self .scopes ), lineno ))
4245
4346 def set_org (self , value : int , lineno : int ):
@@ -46,6 +49,7 @@ def set_org(self, value: int, lineno: int):
4649 if value < 0 or value > self .MAX_MEM :
4750 error (lineno , "Memory ORG out of range [0 .. 65535]. Current value: %i" % value )
4851
52+ self .clear_temporary_labels ()
4953 self .index = self .ORG = value
5054
5155 @staticmethod
@@ -57,7 +61,8 @@ def id_name(label: str, namespace: Optional[str] = None) -> Tuple[str, str]:
5761 if namespace is None :
5862 namespace = asm_gl .NAMESPACE
5963
60- if label .isdecimal (): # temporary labels are just integer numbers
64+ # temporary labels are just integer numbers
65+ if label .isdecimal () or label [- 1 ] in 'BF' and label [:- 1 ].isdecimal ():
6166 return label , namespace
6267
6368 if not label .startswith (DOT ):
@@ -85,6 +90,7 @@ def __set_byte(self, byte: int, lineno: int):
8590 def exit_proc (self , lineno : int ):
8691 """ Exits current procedure. Local labels are transferred to global
8792 scope unless they have been marked as local ones.
93+ Temporary labels are "forgotten", and used ones must be resolved at this point.
8894
8995 Raises an error if no current local context (stack underflow)
9096 """
@@ -112,12 +118,31 @@ def exit_proc(self, lineno: int):
112118
113119 self .local_labels .pop () # Removes current context
114120 self .scopes .pop ()
121+ self .clear_temporary_labels ()
115122
116123 def set_memory_slot (self ):
117124 if self .org not in self .orgs :
118125 self .orgs [self .org ] = [] # Declares an empty memory slot if not already done
119126 self .memory_bytes [self .org ] = 0 # Declares an empty memory slot if not already done
120127
128+ def resolve_temporary_label (self , label : Label ):
129+ if label .direction == - 1 :
130+ idx = bisect_right (self ._tmp_labels_lines , label .lineno )
131+ for line in self ._tmp_labels_lines [:idx ][::- 1 ]:
132+ if label == self ._tmp_labels [line ].get (label .name ):
133+ label .value = self ._tmp_labels [line ][label .name ].value
134+ return
135+ elif label .direction == + 1 :
136+ idx = bisect_left (self ._tmp_labels_lines , label .lineno )
137+ for line in self ._tmp_labels_lines [idx :]:
138+ if label == self ._tmp_labels [line ].get (label .name ):
139+ label .value = self ._tmp_labels [line ][label .name ].value
140+ return
141+
142+ def clear_temporary_labels (self ):
143+ self ._tmp_labels_lines = []
144+ self ._tmp_labels = defaultdict (dict )
145+
121146 def add_instruction (self , instr : Asm ):
122147 """ This will insert an asm instruction at the current memory position
123148 in a t-uple as (mnemonic, params).
@@ -142,8 +167,12 @@ def dump(self):
142167 align = []
143168
144169 for label in self .global_labels .values ():
170+ if label .is_temporary :
171+ self .resolve_temporary_label (label )
172+
145173 if not label .defined :
146- error (label .lineno , "Undefined GLOBAL label '%s'" % label .name )
174+ label_type = 'temporary' if label .is_temporary else 'GLOBAL'
175+ error (label .lineno , f"Undefined { label_type } label '%s'" % label .name )
147176
148177 for i in range (org , max (self .memory_bytes .keys ()) + 1 ):
149178 if gl .has_errors :
@@ -201,6 +230,14 @@ def declare_label(
201230 else :
202231 __DEBUG__ (f"Declaring '{ ex_label } ' in { lineno } " )
203232
233+ if label .isdecimal (): # Temporary label?
234+ assert not self ._tmp_labels_lines or self ._tmp_labels_lines [- 1 ] <= lineno , "Temporary label out of order"
235+ if not self ._tmp_labels_lines or self ._tmp_labels_lines [- 1 ] != lineno :
236+ self ._tmp_labels_lines .append (lineno )
237+
238+ self ._tmp_labels [lineno ][ex_label ] = Label (ex_label , lineno , value , False , namespace , is_address = True )
239+ return
240+
204241 if ex_label in self .local_labels [- 1 ].keys ():
205242 self .local_labels [- 1 ][ex_label ].define (value , lineno )
206243 self .local_labels [- 1 ][ex_label ].is_address = is_address
0 commit comments