def _add_runtime(self): """Add Runtime Functions Adds each runtime function to the list of global functions. """ # The runtime_functions list is defined in the CodeGenerator class for func_name in self.runtime_functions: # Get all parameters for these functions param_ids = [] param_list = self.runtime_functions[func_name] for index, param in enumerate(param_list): # Build up each param, add it to the list id_obj = Identifier(name=param[0], type=param[1], size=None, params=None, mm_ptr=(index + 1)) p_obj = Parameter(id=id_obj, direction=param[2]) param_ids.append(p_obj) # Build the function's identifier func_id = Identifier(name=func_name, type='procedure', size=None, params=param_ids, mm_ptr=1) # Add the function to the global scope of the identifier table self._ids.add(func_id, is_global=True) return
def _parse_program_header(self): """27 """ while not self._accept('keyword', 'the'): try: self._parse_statement() except ParserError: self._resync_at_token('symbol', ';') self._match('symbol', ';') self._match('keyword', 'program') id_name = self._current.value self._match('identifier') # Generate procedure label. This will be stored with the identifier # in place of the mm_ptr attribute since it will not be used label_id = self.get_label_id() # Add the new identifier to the global table id_obj = Identifier(id_name, 'program', None, None, label_id) self._ids.add(id_obj, is_global=True) self._match('keyword', 'is') # Generate the program entry point code self.generate_program_entry(id_obj.name, id_obj.mm_ptr, self.debug) # Push the scope to the program body level self._ids.push_scope(id_obj.name) # Add the program to the base scope so it can be resolved as owner self._ids.add(id_obj) return id_obj
def _parse_procedure_header(self, is_global): """<procedure_header> (Protected) Parses the <procedure_header> language structure. <procedure_header> ::= 'procedure' <identifier> '(' [ <parameter_list> ] ')' Arguments: is_global: Denotes if the procedure is to be globally scoped. """ self._match('keyword', 'procedure') id_name = self._current.value id_line = self._current.line self._match('identifier') self._match('symbol', '(') params = [] if not self._check('symbol', ')'): params = self._parse_parameter_list(params) self._match('symbol', ')') # Generate procedure label. This will be stored with the identifier # in place of the mm_ptr attribute since it will not be used label_id = self.get_label_id() id_obj = Identifier(id_name, 'procedure', None, params, label_id) try: # Add the procedure identifier to the parent and its own table self._ids.add(id_obj, is_global=is_global) self._ids.push_scope(id_obj.name) self._ids.add(id_obj) except ParserNameError: self._name_error('name already declared at this scope', id_name, id_line) # Attempt to add each encountered param at the procedure scope for param in params: try: self._ids.add(param.id, is_global=False) except ParserNameError: self._name_error('name already declared at global scope', param.id.name, id_line) # Define the entry point for the function w/ unique identifier self.generate('%s_%d:' % (id_obj.name, id_obj.mm_ptr)) self.tab_push() # Define the beginning of the function body self.generate('goto %s_%d_begin;' % (id_obj.name, id_obj.mm_ptr)) self.generate('') return id_obj
def _parse_variable_declaration(self, is_global=False, is_param=False): """<variable_declaration> (Protected) Parses the <variable_declaration> language structure. <variable_declaration> ::= <type_mark> <identifier> [ '[' <array_size> ']' ] Arguments: is_global: Denotes if the variable is to be globally scoped. (Default: False) id_table_add: Denotes if the variable is to be added to the identifier table. Returns: The Identifier class object of the variable encountered. """ id_type = self._parse_type_mark() # Stores the array size of the variable var_size = None # Formally match the token to an identifier type var_token = self._match('identifier') if self._accept('symbol', '['): index_type = self._parse_number(generate_code=False) var_size = self._previous.value index_line = self._previous.line # Check the type to make sure this is an integer so that we can # allocate memory appropriately if index_type != 'integer': self._type_error('integer', index_type, index_line) raise ParserTypeError() self._match('symbol', ']') # Get the memory space pointer for this variable. mm_ptr = self.get_mm(var_size, is_param=is_param) # The declaration was valid, add the identifier to the table id_obj = Identifier(var_token.value, id_type, var_size, None, mm_ptr) if not is_param: try: self._ids.add(id_obj, is_global=is_global) except ParserNameError as e: self._name_error(str(e), var_token.value, var_token.line) return id_obj
def _parse_program_header(self): """<program_header> (Protected) Parses the <program_header> language structure. <program_header> ::= 'program' <identifier> 'is' Returns: The id object with information about the procedure identifier. """ self._match('keyword', 'program') id_name = self._current.value self._match('identifier') # Generate procedure label. This will be stored with the identifier # in place of the mm_ptr attribute since it will not be used label_id = self.get_label_id() # Add the new identifier to the global table id = Identifier(id_name, 'program', None, None, label_id) self._ids.add(id, is_global=True) self._match('keyword', 'is') # Push the return addr onto the stack self.comment('Setting program return address', self.debug) self.generate('MM[R[FP]] = (int)&&%s_%d_end;' % (id.name, id.mm_ptr)) # Make the jump to the entry point self.generate('goto %s_%d_begin;' % (id.name, id.mm_ptr)) # Make the main program return self.generate('') self.comment('Creating the program exit point', self.debug) self.generate('%s_%d_end:' % (id.name, id.mm_ptr)) self.tab_push() self.generate('return 0;') self.tab_pop() self.generate('') # Push the scope to the program body level self._ids.push_scope(id.name) # Add the program to the base scope so it can be resolved as owner self._ids.add(id) return id
def _parse_variable_declaration(self, is_global=False, is_param=False): """31""" id_type = self._parse_type_mark() # Stores the array size of the variable var_size = None # Formally match the token to an identifier type var_token = self._match('identifier') if self._accept('symbol', '['): index_type = self._parse_number(generate_code=False) var_size = self._previous.value index_line = self._previous.line # Check the type to make sure this is an integer so that we can # allocate memory appropriately if index_type != 'int': self._type_error('int', index_type, index_line) raise ParserTypeError() self._match('symbol', ']') # Get the memory space pointer for this variable. mm_ptr = self.get_mm(var_size, is_param=is_param) # The declaration was valid, add the identifier to the table id_obj = Identifier(var_token.value, id_type, var_size, None, mm_ptr) if not is_param: try: self._ids.add(id_obj, is_global=is_global) except ParserNameError as e: self._name_error(str(e), var_token.value, var_token.line) return id_obj
def _parse_program_header(self): """<program_header> (Protected) Parses the <program_header> language structure. <program_header> ::= 'program' <identifier> 'is' Returns: The id object with information about the procedure identifier. """ self._match('keyword', 'program') id_name = self._current.value self._match('identifier') # Generate procedure label. This will be stored with the identifier # in place of the mm_ptr attribute since it will not be used label_id = self.get_label_id() # Add the new identifier to the global table id_obj = Identifier(id_name, 'program', None, None, label_id) self._ids.add(id_obj, is_global=True) self._match('keyword', 'is') # Generate the program entry point code self.generate_program_entry(id_obj.name, id_obj.mm_ptr, self.debug) # Push the scope to the program body level self._ids.push_scope(id_obj.name) # Add the program to the base scope so it can be resolved as owner self._ids.add(id_obj) return id_obj