Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Structs #55

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 90 additions & 2 deletions Compiler/Compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
from .Exceptions import BFSyntaxError, BFSemanticError
from .FunctionCompiler import FunctionCompiler
from .Functions import check_function_exists, get_function_object, insert_function_object
from .General import is_token_literal, get_literal_token_code, unpack_literal_tokens_to_array_dimensions
from .General import get_NUM_token_value, is_token_literal, get_literal_token_code, unpack_literal_tokens_to_array_dimensions
from .Globals import get_global_variables_size, get_variable_size, get_variable_dimensions, insert_global_variable, create_variable_from_definition
from .Structs import Struct, insert_struct_object, get_struct_object
from .Lexical_analyzer import analyze
from .LibraryFunctionCompiler import insert_library_functions
from .Parser import Parser
Expand Down Expand Up @@ -43,6 +44,90 @@ def create_function_object(self):
function = FunctionCompiler(function_name, function_tokens)
return function

def create_struct_object(self):
# struct syntax: STRUCT ID LBRACE ((INT | STRUCT ID) ID ((LBRACK NUM RBRACK)+)? SEMICOLON)+ RBRACE SEMICOLON

self.parser.check_next_tokens_are([Token.ID, Token.LBRACE])
struct_name_token = self.parser.next_token()
struct_name = struct_name_token.data
self.parser.advance_token(amount=3) # point to after LBRACE

struct_object = Struct(struct_name, struct_name_token)

defined_field_names = []

token = self.parser.current_token()
while token is not None and token.type in [Token.INT, Token.STRUCT]:
if token.type == Token.STRUCT:
self.parser.check_next_tokens_are([Token.ID, Token.ID])
field_struct_id = self.parser.next_token().data
field_name_token = self.parser.next_token(2)
field_name = field_name_token.data

if self.parser.next_token(3).type == Token.LBRACK:
self.parser.advance_token(amount=3) # point to LBRACK
dimensions = [] # element[i] holds the size of dimension[i]

while self.parser.current_token().type == Token.LBRACK:
self.parser.check_current_tokens_are([Token.LBRACK, Token.NUM, Token.RBRACK])
dimensions.append(get_NUM_token_value(self.parser.next_token()))

self.parser.advance_token(amount=3) # skip LBRACK NUM RBRACK
else:
dimensions = [1]
self.parser.advance_token(amount=3) # point to after ID

self.parser.check_current_tokens_are([Token.SEMICOLON])
self.parser.advance_token() # point to after SEMICOLON

type_obj = {
"type": Token.STRUCT,
"size": get_struct_object(field_struct_id).size,
"id": field_struct_id,
"dimensions": dimensions
}
elif token.type == Token.INT:
self.parser.check_next_tokens_are([Token.ID])
field_name_token = self.parser.next_token()
field_name = field_name_token.data

if self.parser.next_token(2).type == Token.LBRACK:
self.parser.advance_token(amount=2) # point to LBRACK
dimensions = [] # element[i] holds the size of dimension[i]

while self.parser.current_token().type == Token.LBRACK:
self.parser.check_current_tokens_are([Token.LBRACK, Token.NUM, Token.RBRACK])
dimensions.append(get_NUM_token_value(self.parser.next_token()))

self.parser.advance_token(amount=3) # skip LBRACK NUM RBRACK
else:
dimensions = [1]
self.parser.advance_token(amount=2) # point to after ID

self.parser.check_current_tokens_are([Token.SEMICOLON])
self.parser.advance_token() # point to after SEMICOLON

type_obj = {
"type": Token.INT,
"size": 1,
"dimensions": dimensions
}
else:
raise BFSyntaxError("Data type %s is not supported in field" % self.parser.current_token())

if field_name in defined_field_names:
raise BFSemanticError("Member '%s' is already defined" % field_name_token)
defined_field_names += [field_name]

struct_object.add_field(type_obj, field_name)

token = self.parser.current_token()

self.parser.check_current_tokens_are([Token.RBRACE, Token.SEMICOLON])
self.parser.advance_token(amount=2) # point to after SEMICOLON

return struct_object

def compile_global_variable_definition(self):
# INT ID (ASSIGN NUM | (LBRACK NUM RBRACK)+ (ASSIGN LBRACE ... RBRACE)?)? SEMICOLON
# returns code that initializes this variable, and advances pointer according to variable size
Expand Down Expand Up @@ -111,7 +196,7 @@ def process_global_definitions(self):
"""
code = ''
token = self.parser.current_token()
while token is not None and token.type in [Token.VOID, Token.INT, Token.SEMICOLON]:
while token is not None and token.type in [Token.VOID, Token.INT, Token.SEMICOLON, Token.STRUCT]:
if token.type == Token.SEMICOLON: # can have random semicolons ;)
self.parser.advance_token()
token = self.parser.current_token()
Expand All @@ -123,6 +208,9 @@ def process_global_definitions(self):
insert_function_object(function)
elif token.type is Token.INT and self.parser.next_token(next_amount=2).type in [Token.SEMICOLON, Token.ASSIGN, Token.LBRACK]:
code += self.compile_global_variable_definition()
elif token.type == Token.STRUCT:
struct_object = self.create_struct_object()
insert_struct_object(struct_object)
else:
raise BFSyntaxError("Unexpected '%s' after '%s'. Expected '(' (function definition) or one of: '=', ';', '[' (global variable definition)" % (str(self.parser.next_token(next_amount=2)), str(self.parser.next_token())))

Expand Down
Loading