# used to suppress TYPEDEF_NAME after '.', PTR_OP, STRUCT, UNION, ENUM token
last_token = -1
- # this is set to the global scope object before calling yyparse(), and then
- # it tracks the current scope whilst inside functions and block statements
- # note: global scope object will be set in the TranslationUnit after parsing
- scope = None
-
- # used for parsing function_definition or declaration
- # as both contain a declaration_specifier_list and at least one declarator,
- # we don t know what it is until we see the "{" of the function_definition or
- # the "," or ";" of the declaration -- but either way we need to know the
- # declaration_specifier_list in order to do scope analysis of the declarator,
- # so we save the below fields when we parse the declaration_specifier_list
- # then refer to them when we parse the declarators (they must be associated)
- _base_type = None
- storage_class = -1
-
- # new way
# used for parsing function_definition or declaration
# as both contain a declaration_specifier_list and at least one declarator,
# we don t know what it is until we see the "{" of the function_definition or
# (but typedef is ignored for function_definition, as it doesn t make sense)
doing_typedef = False
- # new way
# stack of sets, pushed when entering a new ItemList (TranslationUnit or
# BlockItemList), and containing the identifiers of active typedef names
# note: must be set to [set()] before calling yyparse(), for global scope
# note: shadowing is not implemented, it is impossible to shadow a typedef
typedef_stack = []
-
- # used for parsing function_definition
- # the expression in the "return" statement will be coerced to this type
- return_type = None
-
- # used for parsing switch statement
- # the expression in the "case" statement will be coerced to this type
- switch_type = []
-
- # used for parsing initializer
- # the initializer expression will be coerced to this type, or if it is a
- # compound type, the constituent types will be stacked while parsing { }
- # the items pushed on the stack look like [type, 0, 0] consisting of the
- # type, the index (either an array index or a structure member index, for
- # sequential initialization without designator), and max index seen so far
- initializer_stack = []
-
- # next temporary names for anonymous struct etc, set to 0 before yyparse()
- next_anonymous_name = 0
%}
%%
primary_expression
- : expression_identifier {
- expression_identifier = yy_element_stack[-1].children[0]
- name = expression_identifier.text[0]
- #print('ref', name)
- i = scope
- while i is not None:
- if name in i.identifiers:
- expression_identifier.scope_identifier = i.identifiers[name]
- break
- i = i.enclosing_scope
- else:
- print('undefined identifier:', name)
- assert False
-
- expression_identifier.calc_type()
- expression_identifier.calc_value()
- }
+ : expression_identifier
| constant
| STRING_LITERAL
| '(' expression ')'
postfix_expression
: primary_expression
- | %space (?E{build, t_def.ExpressionIndex}postfix_expression '[' expression ']')
- | %space (?E{build, t_def.ExpressionCall}postfix_expression '(' %space (?E{t_def.ArgumentExpressionList}argument_expression_list_opt) ')') {
- expression_call = yy_element_stack[-1].children[0]
-
- function_type = expression_call.children[0].type
- assert isinstance(function_type, t_def.TypeFunction)
- actual_parameters = expression_call.children[1]
-
- if isinstance(function_type, t_def.TypeFunctionANSI):
- n_formal_parameters = len(function_type.formal_parameters)
- if function_type.varargs:
- assert len(actual_parameters.children) >= n_formal_parameters
- else:
- assert len(actual_parameters.children) == n_formal_parameters
-
- # process typed parameters
- for i in range(n_formal_parameters):
- actual_parameters.children[i] = t_def.add_cast(
- function_type.formal_parameters[i],
- actual_parameters.children[i]
- )
- elif isinstance(function_type, t_def.TypeFunctionKAndR):
- n_formal_parameters = 0 # for non-ANSI, treat all parameters as varargs
- else:
- assert False
-
- # process remaining (untyped) parameters
- for i in range(n_formal_parameters, len(actual_parameters.children)):
- rank = actual_parameters.children[i].type.rank
- if rank >= 0 and rank < t_def.INT_RANK:
- actual_parameters.children[i] = t_def.add_cast(
- t_def.type_signed_int,
- actual_parameters.children[i]
- )
- elif rank >= t_def.FLOAT_RANK and rank < t_def.DOUBLE_RANK:
- actual_parameters.children[i] = t_def.add_cast(
- t_def.rank_to_type[rank + t_def.DOUBLE_RANK - t_def.FLOAT_RANK],
- actual_parameters.children[i]
- )
- }
- | %space (?E{build, t_def.ExpressionMember}postfix_expression '.' member_identifier)
- | %space (?E{build, t_def.ExpressionMemberDereference}postfix_expression PTR_OP member_identifier)
- | %space (?E{build, t_def.ExpressionPostIncrement}postfix_expression INC_OP)
- | %space (?E{build, t_def.ExpressionPostDecrement}postfix_expression DEC_OP)
- | %space (?E{build, t_def.ExpressionArrayOrStruct}'(' type_name ')' {
- type_name = yy_element_stack[-4].children[0]
- assert isinstance(type_name, t_def.TypeName)
-
- # this global variable is needed whilst parsing the initializer
- assert len(initializer_stack) == 0
- initializer_stack.append([type_name.type, 0, 0])
- } '{' %space (?E{t_def.DesignatorInitializerList}designator_initializer_list_comma_opt) '}') {
- # this global variable was needed whilst parsing the initializer
- _, _, max_index = initializer_stack.pop()
- assert len(initializer_stack) == 0
-
- expression_array_or_struct_or_union = yy_element_stack[-1].children[0]
- _type = expression_array_or_struct_or_union.children[0].type
- assert (
- isinstance(_type, t_def.TypeArray) or
- isinstance(_type, t_def.TypeStructOrUnion)
- )
-
- if (
- isinstance(_type, t_def.TypeArray) and
- _type.element_count == -1 and
- len(init_declarator.children) >= 2
- ):
- # size of indeterminate sized array can be deduced from initializer
- element_size = _type.element_type.size
- assert element_size >= 0 # must be of determinate size
- _type.size = max_index * element_size
- _type.element_count = max_index
- else:
- assert _type.size >= 0 # must be of determinate size
- }
+ | %space (?E{t_def.ExpressionIndex}postfix_expression '[' expression ']')
+ | %space (?E{t_def.ExpressionCall}postfix_expression '(' %space (?E{t_def.ArgumentExpressionList}argument_expression_list_opt) ')')
+ | %space (?E{t_def.ExpressionMember}postfix_expression '.' member_identifier)
+ | %space (?E{t_def.ExpressionMemberDereference}postfix_expression PTR_OP member_identifier)
+ | %space (?E{t_def.ExpressionPostIncrement}postfix_expression INC_OP)
+ | %space (?E{t_def.ExpressionPostDecrement}postfix_expression DEC_OP)
+ | %space (?E{t_def.ExpressionArrayOrStruct}'(' type_name ')' '{' %space (?E{t_def.DesignatorInitializerList}designator_initializer_list_comma_opt) '}')
;
argument_expression_list_opt
unary_expression
: postfix_expression
- | %space (?E{build, t_def.ExpressionPreIncrement}INC_OP unary_expression)
- | %space (?E{build, t_def.ExpressionPreDecrement}DEC_OP unary_expression)
- | %space (?E{build, t_def.ExpressionAddressOf}'&' cast_expression)
- | %space (?E{build, t_def.ExpressionDereference}'*' cast_expression)
- | %space (?E{build, t_def.ExpressionPlus}'+' cast_expression)
- | %space (?E{build, t_def.ExpressionMinus}'-' cast_expression)
- | %space (?E{build, t_def.ExpressionBitwiseNot}'~' cast_expression)
- | %space (?E{build, t_def.ExpressionLogicalNot}'!' cast_expression)
- | %space (?E{build, t_def.ExpressionSizeOfExpression}SIZEOF unary_expression)
- | %space (?E{build, t_def.ExpressionSizeOfType}SIZEOF '(' type_name ')')
- | %space (?E{build, t_def.ExpressionAlignOfType}ALIGNOF '(' type_name ')')
+ | %space (?E{t_def.ExpressionPreIncrement}INC_OP unary_expression)
+ | %space (?E{t_def.ExpressionPreDecrement}DEC_OP unary_expression)
+ | %space (?E{t_def.ExpressionAddressOf}'&' cast_expression)
+ | %space (?E{t_def.ExpressionDereference}'*' cast_expression)
+ | %space (?E{t_def.ExpressionPlus}'+' cast_expression)
+ | %space (?E{t_def.ExpressionMinus}'-' cast_expression)
+ | %space (?E{t_def.ExpressionBitwiseNot}'~' cast_expression)
+ | %space (?E{t_def.ExpressionLogicalNot}'!' cast_expression)
+ | %space (?E{t_def.ExpressionSizeOfExpression}SIZEOF unary_expression)
+ | %space (?E{t_def.ExpressionSizeOfType}SIZEOF '(' type_name ')')
+ | %space (?E{t_def.ExpressionAlignOfType}ALIGNOF '(' type_name ')')
;
cast_expression
: unary_expression
- | %space (?E{build, t_def.ExpressionCast}'(' type_name ')' cast_expression)
+ | %space (?E{t_def.ExpressionCast}'(' type_name ')' cast_expression)
;
multiplicative_expression
: cast_expression
- | %space (?E{build, t_def.ExpressionMultiply}multiplicative_expression '*' cast_expression)
- | %space (?E{build, t_def.ExpressionDivide}multiplicative_expression '/' cast_expression)
- | %space (?E{build, t_def.ExpressionModulo}multiplicative_expression '%' cast_expression)
+ | %space (?E{t_def.ExpressionMultiply}multiplicative_expression '*' cast_expression)
+ | %space (?E{t_def.ExpressionDivide}multiplicative_expression '/' cast_expression)
+ | %space (?E{t_def.ExpressionModulo}multiplicative_expression '%' cast_expression)
;
additive_expression
: multiplicative_expression
- | %space (?E{build, t_def.ExpressionAdd}additive_expression '+' multiplicative_expression)
- | %space (?E{build, t_def.ExpressionSubtract}additive_expression '-' multiplicative_expression)
+ | %space (?E{t_def.ExpressionAdd}additive_expression '+' multiplicative_expression)
+ | %space (?E{t_def.ExpressionSubtract}additive_expression '-' multiplicative_expression)
;
shift_expression
: additive_expression
- | %space (?E{build, t_def.ExpressionShiftLeft}shift_expression LEFT_OP additive_expression)
- | %space (?E{build, t_def.ExpressionShiftRight}shift_expression RIGHT_OP additive_expression)
+ | %space (?E{t_def.ExpressionShiftLeft}shift_expression LEFT_OP additive_expression)
+ | %space (?E{t_def.ExpressionShiftRight}shift_expression RIGHT_OP additive_expression)
;
relational_expression
: shift_expression
- | %space (?E{build, t_def.ExpressionLessThan}relational_expression '<' shift_expression)
- | %space (?E{build, t_def.ExpressionGreaterThan}relational_expression '>' shift_expression)
- | %space (?E{build, t_def.ExpressionLessThanOrEqual}relational_expression LE_OP shift_expression)
- | %space (?E{build, t_def.ExpressionGreaterThanOrEqual}relational_expression GE_OP shift_expression)
+ | %space (?E{t_def.ExpressionLessThan}relational_expression '<' shift_expression)
+ | %space (?E{t_def.ExpressionGreaterThan}relational_expression '>' shift_expression)
+ | %space (?E{t_def.ExpressionLessThanOrEqual}relational_expression LE_OP shift_expression)
+ | %space (?E{t_def.ExpressionGreaterThanOrEqual}relational_expression GE_OP shift_expression)
;
equality_expression
: relational_expression
- | %space (?E{build, t_def.ExpressionEqual}equality_expression EQ_OP relational_expression)
- | %space (?E{build, t_def.ExpressionNotEqual}equality_expression NE_OP relational_expression)
+ | %space (?E{t_def.ExpressionEqual}equality_expression EQ_OP relational_expression)
+ | %space (?E{t_def.ExpressionNotEqual}equality_expression NE_OP relational_expression)
;
and_expression
: equality_expression
- | %space (?E{build, t_def.ExpressionBitwiseAnd}and_expression '&' equality_expression)
+ | %space (?E{t_def.ExpressionBitwiseAnd}and_expression '&' equality_expression)
;
exclusive_or_expression
: and_expression
- | %space (?E{build, t_def.ExpressionExclusiveOr}exclusive_or_expression '^' and_expression)
+ | %space (?E{t_def.ExpressionExclusiveOr}exclusive_or_expression '^' and_expression)
;
inclusive_or_expression
: exclusive_or_expression
- | %space (?E{build, t_def.ExpressionBitwiseOr}inclusive_or_expression '|' exclusive_or_expression)
+ | %space (?E{t_def.ExpressionBitwiseOr}inclusive_or_expression '|' exclusive_or_expression)
;
logical_and_expression
: inclusive_or_expression
- | %space (?E{build, t_def.ExpressionLogicalAnd}logical_and_expression AND_OP inclusive_or_expression)
+ | %space (?E{t_def.ExpressionLogicalAnd}logical_and_expression AND_OP inclusive_or_expression)
;
logical_or_expression
: logical_and_expression
- | %space (?E{build, t_def.ExpressionLogicalOr}logical_or_expression OR_OP logical_and_expression)
+ | %space (?E{t_def.ExpressionLogicalOr}logical_or_expression OR_OP logical_and_expression)
;
conditional_expression
: logical_or_expression
- | %space (?E{build, t_def.ExpressionConditional}logical_or_expression '?' expression ':' conditional_expression)
+ | %space (?E{t_def.ExpressionConditional}logical_or_expression '?' expression ':' conditional_expression)
;
/* occurs in array declarator */
assignment_expression_or_asterisk_opt
- : %space (?E{build, t_def.ExpressionEmpty})
+ : %space (?E{t_def.ExpressionEmpty})
| %space (?E{t_def.ExpressionAsterisk}'*')
- | assignment_expression {
- container = yy_element_stack[-1]
- assert isinstance(container.children[0], t_def.Expression)
- if container.children[0].type != t_def.type_size_t:
- container.children[0] = t_def.add_cast(
- t_def.type_size_t,
- container.children[0]
- )
- }
+ | assignment_expression
;
assignment_expression
: conditional_expression
- | %space (?E{build, t_def.ExpressionEqualAssignment}unary_expression '=' assignment_expression)
- | %space (?E{build, t_def.ExpressionMultiplyAssignment}unary_expression MUL_ASSIGN assignment_expression)
- | %space (?E{build, t_def.ExpressionDivideAssignment}unary_expression DIV_ASSIGN assignment_expression)
- | %space (?E{build, t_def.ExpressionModuloAssignment}unary_expression MOD_ASSIGN assignment_expression)
- | %space (?E{build, t_def.ExpressionAddAssignment}unary_expression ADD_ASSIGN assignment_expression)
- | %space (?E{build, t_def.ExpressionSubtractAssignment}unary_expression SUB_ASSIGN assignment_expression)
- | %space (?E{build, t_def.ExpressionShiftLeftAssignment}unary_expression LEFT_ASSIGN assignment_expression)
- | %space (?E{build, t_def.ExpressionShiftRightAssignment}unary_expression RIGHT_ASSIGN assignment_expression)
- | %space (?E{build, t_def.ExpressionBitwiseAndAssignment}unary_expression AND_ASSIGN assignment_expression)
- | %space (?E{build, t_def.ExpressionExclusiveOrAssignment}unary_expression XOR_ASSIGN assignment_expression)
- | %space (?E{build, t_def.ExpressionBitwiseOrAssignment}unary_expression OR_ASSIGN assignment_expression)
+ | %space (?E{t_def.ExpressionEqualAssignment}unary_expression '=' assignment_expression)
+ | %space (?E{t_def.ExpressionMultiplyAssignment}unary_expression MUL_ASSIGN assignment_expression)
+ | %space (?E{t_def.ExpressionDivideAssignment}unary_expression DIV_ASSIGN assignment_expression)
+ | %space (?E{t_def.ExpressionModuloAssignment}unary_expression MOD_ASSIGN assignment_expression)
+ | %space (?E{t_def.ExpressionAddAssignment}unary_expression ADD_ASSIGN assignment_expression)
+ | %space (?E{t_def.ExpressionSubtractAssignment}unary_expression SUB_ASSIGN assignment_expression)
+ | %space (?E{t_def.ExpressionShiftLeftAssignment}unary_expression LEFT_ASSIGN assignment_expression)
+ | %space (?E{t_def.ExpressionShiftRightAssignment}unary_expression RIGHT_ASSIGN assignment_expression)
+ | %space (?E{t_def.ExpressionBitwiseAndAssignment}unary_expression AND_ASSIGN assignment_expression)
+ | %space (?E{t_def.ExpressionExclusiveOrAssignment}unary_expression XOR_ASSIGN assignment_expression)
+ | %space (?E{t_def.ExpressionBitwiseOrAssignment}unary_expression OR_ASSIGN assignment_expression)
;
expression_opt
expression
: assignment_expression
- | %space (?E{build, t_def.ExpressionComma}expression ',' assignment_expression)
+ | %space (?E{t_def.ExpressionComma}expression ',' assignment_expression)
;
/* occurs in enumerator */
equals_constant_expression_opt
:
- | '=' constant_expression {
- container = yy_element_stack[-1]
- assert isinstance(container.children[0], t_def.Expression)
- if container.children[0].type != t_def.type_signed_int:
- container.children[0] = t_def.add_cast(
- t_def.type_signed_int,
- container.children[0]
- )
- }
+ | '=' constant_expression
;
constant_expression
declaration
: %space (?E{t_def.Declaration}declaration_specifier_list1 %space (?E{t_def.InitDeclaratorList}init_declarator_list_opt) ';') {
- global _base_type, storage_class
-
- # in general the storage class is taken from the ScopeIdentifier when we
- # regenerate the redundant information, but we also need some information
- # about the declaration itself to know if the declaration is a forward one
- declaration = yy_element_stack[-1].children[0]
- declaration.storage_class = storage_class
-
- # these globals were needed whilst parsing the list of init declarators
- _base_type = None
- storage_class = -1
-
- # new way
global doing_typedef
# this global is set by declaration_specifier_list1 if doing typedef,
/* intercept declaration_specifier_list to save _base_type and storage_class */
declaration_specifier_list1
: %space (?E{t_def.DeclarationSpecifierList}declaration_specifier_list) {
- global _base_type, storage_class
-
- declaration_specifier_list = yy_element_stack[-1].children[0]
-
- # these globals are needed whilst parsing the function body or init
- # declarators, we don t know which until we see the '{', ',' or ';'
- _base_type = declaration_specifier_list.get_base_type()
- storage_class = declaration_specifier_list.get_storage_class()
-
- # new way
global doing_typedef
declaration_specifier_list = yy_element_stack[-1].children[0]
init_declarator
: %space (?E{t_def.InitDeclarator}declarator {
- declarator = yy_element_stack[-2].children[0]
- assert isinstance(declarator, t_def.Declarator)
-
- # we refer to the global variables for _base_type and storage_class
- name, _type = declarator.get_name_and_type(_base_type)
- #print('decl', name)
-
- if name in scope.identifiers:
- scope_identifier = scope.identifiers[name]
- assert scope_identifier.type == _type
- else:
- scope_identifier = t_def.Scope.Identifier(
- name = name,
- type = _type,
- storage_class = t_def.STORAGE_CLASS_NONE
- )
- scope.identifiers[name] = scope_identifier
- # save scope_identifier for InitDeclarator when constructed
- # save storage_class for extern, initializer, array size checks
- $$ = (scope_identifier, storage_class)
-
- storage_class1 = storage_class
- if isinstance(_type, t_def.TypeFunction):
- assert storage_class1 in {
- t_def.STORAGE_CLASS_NONE,
- t_def.STORAGE_CLASS_EXTERN,
- t_def.STORAGE_CLASS_STATIC
- }
- elif storage_class1 not in {
- t_def.STORAGE_CLASS_EXTERN,
- t_def.STORAGE_CLASS_TYPEDEF
- }:
- if isinstance(_type, t_def.TypeArray):
- assert _type.element_type.size >= 0 # must be of determinate size
-
- assert not scope_identifier.defined
- scope_identifier.defined = True
-
- if (
- scope.enclosing_scope is not None and
- storage_class1 == t_def.STORAGE_CLASS_NONE
- ):
- storage_class1 = t_def.STORAGE_CLASS_AUTO
-
- # don't do this here -- we don't have size of indeterminate array yet
- #align_m1 = _type.align - 1
- #scope.size = (scope.size + align_m1) & ~align_m1
- #scope_identifier.offset = scope.size
- #if _type.size >= 0: # unknown size treated as 0 bytes (not correct!!)
- # scope.size += _type.size
- elif storage_class1 == t_def.STORAGE_CLASS_TYPEDEF: # TEMPORARY
- assert not scope_identifier.defined # TEMPORARY
- scope_identifier.defined = True # TEMPORARY
-
- if storage_class1 == t_def.STORAGE_CLASS_NONE:
- pass
- elif scope_identifier.storage_class == t_def.STORAGE_CLASS_NONE:
- scope_identifier.storage_class = storage_class1
- else:
- assert scope_identifier.storage_class == storage_class1
-
- # this global variable is needed whilst parsing the initializer
- assert len(initializer_stack) == 0
- initializer_stack.append([_type, 0, 0])
-
- # new way
# if doing typedef, insert the new typedef into top of typedef_stack
if doing_typedef:
declarator = yy_element_stack[-2].children[0]
declarator_identifier = t_def.get_declarator_identifier(declarator)
assert declarator_identifier is not None
typedef_stack[-1].add(declarator_identifier.text[0])
- } equals_initializer_opt) {
- # scope_identifier was saved for InitDeclarator when constructed
- # storage_class was saved for extern, initializer, array size checks
- scope_identifier, storage_class = $2
-
- init_declarator = yy_element_stack[-1].children[0]
- init_declarator.scope_identifier = scope_identifier
-
- # this global variable was needed whilst parsing the initializer
- _, _, max_index = initializer_stack.pop()
- assert len(initializer_stack) == 0
-
- _type = scope_identifier.type
- if isinstance(_type, t_def.TypeFunction):
- assert len(init_declarator.children) < 2 # can t have initializer
- elif storage_class in {
- t_def.STORAGE_CLASS_EXTERN,
- t_def.STORAGE_CLASS_TYPEDEF
- }:
- assert len(init_declarator.children) < 2 # can t have initializer
- else:
- if (
- isinstance(_type, t_def.TypeArray) and
- _type.element_count == -1 and
- len(init_declarator.children) >= 2
- ):
- # size of indeterminate sized array can be deduced from initializer
- element_size = _type.element_type.size
- assert element_size >= 0 # must be of determinate size
- _type.size = max_index * element_size
- _type.element_count = max_index
-
- assert _type.size >= 0 # must be of determinate size
- align_m1 = _type.align - 1
- scope.size = (scope.size + align_m1) & ~align_m1
- scope_identifier.offset = scope.size
- scope.size += _type.size
- }
+ } equals_initializer_opt)
;
storage_class_specifier
;
struct_specifier
- : %space (?E{t_def.StructSpecifier}STRUCT tag_identifier_opt '{' %space (?E{t_def.StructDeclarationList}struct_declaration_list_opt) '}') {
- global next_anonymous_name
-
- struct_specifier = yy_element_stack[-1].children[0]
- name = struct_specifier.children[0].text[0]
- if len(name) == 0:
- name = f'${next_anonymous_name:d}'
- next_anonymous_name += 1
-
- if name in scope.struct_tags:
- scope_tag = scope.struct_tags[name]
- _type = scope_tag.type
- else:
- _type = t_def.TypeStruct()
- scope_tag = t_def.Scope.Tag(name = name, type = _type)
- scope.struct_tags[name] = scope_tag
- struct_specifier.scope_tag = scope_tag
-
- assert not scope_tag.defined
- scope_tag.defined = True
-
- members = []
- member_name_to_index = {}
- size = 0
- align = 1
- for i in struct_specifier.children[1].children:
- _base_type = i.children[0].get_base_type()
- for j in i.children[1].children:
- member_name, member_type = j.get_name_and_type(_base_type)
- if len(member_name) == 0: # used for bit fields with no name
- member_name = f'${next_anonymous_name:d}'
- next_anonymous_name += 1
- assert member_name not in member_name_to_index
- assert member_type.size >= 0 # must be of determinate size
- align_m1 = member_type.align - 1
- size = (size + align_m1) & ~align_m1
- member_name_to_index[member_name] = len(members)
- members.append(
- t_def.TypeStructOrUnion.Member(
- name = member_name,
- type = member_type,
- offset = size
- )
- )
- size += member_type.size
- align = max(align, member_type.align)
-
- # make the size a multiple of the alignment
- align_m1 = align - 1
- size = (size + align_m1) & ~align_m1
-
- _type.size = size
- _type.align = align
- _type.members = members
- _type.member_name_to_index = member_name_to_index
- }
- | %space (?E{t_def.StructSpecifier}STRUCT tag_identifier) {
- struct_specifier = yy_element_stack[-1].children[0]
- name = struct_specifier.children[0].text[0]
-
- i = scope
- while i is not None:
- if name in i.struct_tags:
- scope_tag = i.struct_tags[name]
- _type = scope_tag.type
- break
- i = i.enclosing_scope
- else:
- _type = t_def.TypeStruct()
- scope_tag = t_def.Scope.Tag(name = name, type = _type)
- scope.struct_tags[name] = scope_tag
- struct_specifier.scope_tag = scope_tag
- }
+ : %space (?E{t_def.StructSpecifier}STRUCT tag_identifier_opt '{' %space (?E{t_def.StructDeclarationList}struct_declaration_list_opt) '}')
+ | %space (?E{t_def.StructSpecifier}STRUCT tag_identifier)
;
union_specifier
- : %space (?E{t_def.UnionSpecifier}UNION tag_identifier_opt '{' %space (?E{t_def.StructDeclarationList}struct_declaration_list_opt) '}') {
- global next_anonymous_name
-
- union_specifier = yy_element_stack[-1].children[0]
- name = union_specifier.children[0].text[0]
- if len(name) == 0:
- name = f'${next_anonymous_name:d}'
- next_anonymous_name += 1
-
- if name in scope.union_tags:
- scope_tag = scope.union_tags[name]
- _type = scope_tag.type
- else:
- _type = t_def.TypeUnion()
- scope_tag = t_def.Scope.Tag(name = name, type = _type)
- scope.union_tags[name] = scope_tag
- union_specifier.scope_tag = scope_tag
-
- assert not scope_tag.defined
- scope_tag.defined = True
-
- members = []
- member_name_to_index = {}
- size = 0
- align = 1
- for i in union_specifier.children[1].children:
- _base_type = i.children[0].get_base_type()
- for j in i.children[1].children:
- member_name, member_type = j.get_name_and_type(_base_type)
- assert member_name not in member_name_to_index
- assert member_type.size >= 0 # must be of determinate size
- member_name_to_index[member_name] = len(members)
- members.append(
- t_def.TypeStructOrUnion.Member(
- name = member_name,
- type = member_type,
- offset = 0
- )
- )
- size = max(size, member_type.size)
- align = max(align, member_type.align)
-
- # make the size a multiple of the alignment
- align_m1 = align - 1
- size = (size + align_m1) & ~align_m1
-
- _type.size = size
- _type.align = align
- _type.members = members
- _type.member_name_to_index = member_name_to_index
- }
- | %space (?E{t_def.UnionSpecifier}UNION tag_identifier) {
- union_specifier = yy_element_stack[-1].children[0]
- name = union_specifier.children[0].text[0]
-
- i = scope
- while i is not None:
- if name in i.union_tags:
- scope_tag = i.union_tags[name]
- _type = scope_tag.type
- break
- i = i.enclosing_scope
- else:
- _type = t_def.TypeUnion()
- scope_tag = t_def.Scope.Tag(name = name, type = _type)
- scope.union_tags[name] = scope_tag
- union_specifier.scope_tag = scope_tag
- }
+ : %space (?E{t_def.UnionSpecifier}UNION tag_identifier_opt '{' %space (?E{t_def.StructDeclarationList}struct_declaration_list_opt) '}')
+ | %space (?E{t_def.UnionSpecifier}UNION tag_identifier)
;
struct_declaration_list_opt
;
struct_declarator
- : %space (?E{t_def.StructDeclarator}declarator_opt ':' constant_expression) {
- struct_declarator = yy_element_stack[-1].children[0]
- if struct_declarator.children[1].type != t_def.type_signed_int:
- struct_declarator.children[1] = t_def.add_cast(
- t_def.type_signed_int,
- struct_declarator.children[1]
- )
- }
+ : %space (?E{t_def.StructDeclarator}declarator_opt ':' constant_expression)
| declarator
;
enum_specifier
- : %space (?E{t_def.EnumSpecifier}ENUM tag_identifier_opt '{' %space (?E{t_def.EnumeratorList}enumerator_list_comma_opt) '}') {
- global next_anonymous_name
-
- enum_specifier = yy_element_stack[-1].children[0]
- name = enum_specifier.children[0].text[0]
- if len(name) == 0:
- name = f'${next_anonymous_name:d}'
- next_anonymous_name += 1
-
- if name in scope.enum_tags:
- scope_tag = scope.enum_tags[name]
- _type = scope_tag.type
- else:
- _type = t_def.TypeEnum(
- rank = t_def.INT_RANK,
- size = t_def.INT_SIZE,
- align = t_def.INT_ALIGN
- )
- scope_tag = t_def.Scope.Tag(name = name, type = _type)
- scope.enum_tags[name] = scope_tag
- enum_specifier.scope_tag = scope_tag
-
- assert not scope_tag.defined
- scope_tag.defined = True
-
- members = {}
- value = 0
- for i in enum_specifier.children[1].children:
- member_name = i.children[0].text[0]
- assert member_name not in members
- if len(i.children) >= 2:
- expression = i.children[1]
- assert expression.type == t_def.type_signed_int
- assert isinstance(expression.value, t_def.ValueInt)
- value = expression.value.value
- members[member_name] = t_def.TypeEnum.Member(
- name = member_name,
- value = value
- )
-
- assert member_name not in scope.identifiers
- scope.identifiers[member_name] = t_def.Scope.Identifier(
- name = member_name,
- type = _type,
- storage_class = t_def.STORAGE_CLASS_ENUM_MEMBER,
- defined = True
- )
-
- value += 1
- _type.members = members
- }
- | %space (?E{t_def.EnumSpecifier}ENUM tag_identifier) {
- enum_specifier = yy_element_stack[-1].children[0]
- name = enum_specifier.children[0].text[0]
-
- i = scope
- while i is not None:
- if name in i.enum_tags:
- scope_tag = i.enum_tags[name]
- _type = scope_tag.type
- break
- i = i.enclosing_scope
- else:
- _type = t_def.TypeEnum(
- rank = t_def.INT_RANK,
- size = t_def.INT_SIZE,
- align = t_def.INT_ALIGN
- )
- scope_tag = t_def.Scope.Tag(name = name, type = _type)
- scope.enum_tags[name] = scope_tag
- enum_specifier.scope_tag = scope_tag
- }
+ : %space (?E{t_def.EnumSpecifier}ENUM tag_identifier_opt '{' %space (?E{t_def.EnumeratorList}enumerator_list_comma_opt) '}')
+ | %space (?E{t_def.EnumSpecifier}ENUM tag_identifier)
;
enumerator_list_comma_opt
alignment_specifier
: %space (?E{t_def.AlignAsType}ALIGNAS '(' type_name ')')
- | %space (?E{t_def.AlignAsExpression}ALIGNAS '(' constant_expression ')') {
- align_as_expression = yy_element_stack[-1].children[0]
- if align_as_expression.children[0].type != t_def.type_size_t:
- align_as_expression.children[0] = t_def.add_cast(
- t_def.type_size_t,
- align_as_expression.children[0]
- )
- }
+ | %space (?E{t_def.AlignAsExpression}ALIGNAS '(' constant_expression ')')
;
declarator_opt
;
parameter_declaration
- : %space (?E{t_def.ParameterDeclaration}(?E{t_def.DeclarationSpecifierList}declaration_specifier_list) declarator) {
- parameter_declaration = yy_element_stack[-1].children[0]
-
- (
- parameter_declaration.name,
- parameter_declaration.type
- ) = parameter_declaration.children[1].get_name_and_type(
- parameter_declaration.children[0].get_base_type()
- )
- assert len(parameter_declaration.name)
- }
- | %space (?E{t_def.ParameterDeclaration}(?E{t_def.DeclarationSpecifierList}declaration_specifier_list) abstract_declarator) {
- parameter_declaration = yy_element_stack[-1].children[0]
-
- (
- parameter_declaration.name,
- parameter_declaration.type
- ) = parameter_declaration.children[1].get_name_and_type(
- parameter_declaration.children[0].get_base_type()
- )
- assert len(parameter_declaration.name) == 0
- }
+ : %space (?E{t_def.ParameterDeclaration}(?E{t_def.DeclarationSpecifierList}declaration_specifier_list) declarator)
+ | %space (?E{t_def.ParameterDeclaration}(?E{t_def.DeclarationSpecifierList}declaration_specifier_list) abstract_declarator)
;
identifier_list_opt
;
type_name
- : %space (?E{t_def.TypeName}(?E{t_def.SpecifierQualifierList}specifier_qualifier_list) abstract_declarator) {
- type_name = yy_element_stack[-1].children[0]
-
- name, type_name.type = type_name.children[1].get_name_and_type(
- type_name.children[0].get_base_type()
- )
- assert len(name) == 0
- }
+ : %space (?E{t_def.TypeName}(?E{t_def.SpecifierQualifierList}specifier_qualifier_list) abstract_declarator)
;
abstract_declarator
;
initializer
- : %space (?E{t_def.InitializerArrayOrStruct}'{' %space (?E{t_def.DesignatorInitializerList}designator_initializer_list_comma_opt) '}') {
- initializer_array_or_struct = yy_element_stack[-1].children[0]
- initializer_array_or_struct.type = initializer_stack[-1][0]
- }
- | %space (?E{t_def.InitializerExpression}assignment_expression) {
- initializer_expression = yy_element_stack[-1].children[0]
- if initializer_expression.children[0].type != initializer_stack[-1][0]:
- initializer_expression.children[0] = t_def.add_cast(
- initializer_stack[-1][0],
- initializer_expression.children[0]
- )
- initializer_expression.type = initializer_stack[-1][0]
- }
+ : %space (?E{t_def.InitializerArrayOrStruct}'{' %space (?E{t_def.DesignatorInitializerList}designator_initializer_list_comma_opt) '}')
+ | %space (?E{t_def.InitializerExpression}assignment_expression)
;
designator_initializer_list_comma_opt
;
designator_initializer
- : %space (?E{t_def.DesignatorInitializer}designator_list_equals_opt {
- designator_list = yy_element_stack[-2].children[0]
- assert isinstance(designator_list, t_def.DesignatorList)
-
- _type, index, max_index = initializer_stack[-1]
- if len(designator_list.children):
- # with designator, the designator says which element to fill
- # note: this resets index position, but only for the first designator
- # for example, [1][3] resets index position to 1, and the next is [2]
- indices = []
- for i in designator_list.children:
- if isinstance(i, t_def.DesignatorIndex):
- assert isinstance(_type, t_def.TypeArray)
-
- # get numeric index from designator
- expression = i.children[0]
- assert expression.type == t_def.type_ssize_t
- assert isinstance(expression.value, t_def.ValueInt)
- j = expression.value.value
-
- assert j >= 0
- assert _type.element_count == -1 or j < _type.element_count
- _type = _type.element_type
- elif isinstance(i, t_def.DesignatorMember):
- assert isinstance(_type, t_def.TypeStructOrUnion)
- member_identifier = i.children[0]
- j = _type.member_name_to_index[member_identifier.text[0]]
- member_identifier.type = _type
- member_identifier.index = j
- _type = _type.members[j].type
- else:
- assert False
- indices.append(j)
- else:
- # without designator, the elements are filled in sequentially
- if isinstance(_type, t_def.TypeArray):
- assert _type.element_count == -1 or index < _type.element_count
- _type =_type.element_type
- elif isinstance(_type, t_def.TypeStructOrUnion):
- assert index < len(_type.members)
- _type =_type.members[index].type
- else:
- assert False
- indices = [index]
- $$ = indices # for DesignatorInitializer when constructed
- index = indices[0] + 1
- initializer_stack[-1][1] = index
- if index > max_index:
- initializer_stack[-1][2] = index
- initializer_stack.append([_type, 0, 0])
- } initializer) {
- initializer_stack.pop()
-
- designator_initializer = yy_element_stack[-1].children[0]
- designator_initializer.type = initializer_stack[-1][0]
- designator_initializer.indices = $2
- }
+ : %space (?E{t_def.DesignatorInitializer}designator_list_equals_opt initializer)
;
designator_list_equals_opt
;
designator
- : %space (?E{t_def.DesignatorIndex}'[' constant_expression ']') {
- designator_index = yy_element_stack[-1].children[0]
- if designator_index.children[0].type != t_def.type_ssize_t:
- designator_index.children[0] = t_def.add_cast(
- t_def.type_ssize_t,
- designator_index.children[0]
- )
- }
+ : %space (?E{t_def.DesignatorIndex}'[' constant_expression ']')
| %space (?E{t_def.DesignatorMember}'.' member_identifier)
;
static_assert_declaration
- : %space (?E{t_def.StaticAssertDeclaration}STATIC_ASSERT '(' constant_expression ',' STRING_LITERAL ')' ';') {
- static_assert_declaration = yy_element_stack[-1].children[0]
- if static_assert_declaration.children[0].type != t_def.type_bool:
- static_assert_declaration.children[0] = t_def.add_cast(
- t_def.type_bool,
- static_assert_declaration.children[0]
- )
- }
+ : %space (?E{t_def.StaticAssertDeclaration}STATIC_ASSERT '(' constant_expression ',' STRING_LITERAL ')' ';')
;
statement
: %space (?E{t_def.StatementLabel}identifier ':' statement)
- | %space (?E{t_def.StatementCase}CASE constant_expression ':' statement) {
- assert len(switch_type) # can only occur within switch
- statement_case = yy_element_stack[-1].children[0]
- if statement_case.children[0].type != switch_type[-1]:
- statement_case.children[0] = t_def.add_cast(
- switch_type[-1],
- statement_case.children[0]
- )
- }
+ | %space (?E{t_def.StatementCase}CASE constant_expression ':' statement)
| %space (?E{t_def.StatementDefault}DEFAULT ':' statement)
| %space (?E{t_def.StatementBlock}'{' {
- global scope
-
- scope = t_def.Scope(enclosing_scope = scope)
-
- # new way
typedef_stack.append(set())
} %space (?E{t_def.BlockItemList}block_item_list_opt) '}') {
- global scope
-
- statement_block = yy_element_stack[-1].children[0]
- statement_block.children[0].scope = scope
- scope = scope.enclosing_scope
-
- # new way
typedef_stack.pop()
}
- | %space (?E{t_def.StatementExpression}expression_opt ';') {
- statement_expression = yy_element_stack[-1].children[0]
- if not isinstance(statement_expression.children[0].type, t_def.TypeVoid):
- statement_expression.children[0] = t_def.add_cast(
- t_def.type_void,
- statement_expression.children[0]
- )
- }
- | %space (?E{t_def.StatementIf}IF '(' expression ')' statement ELSE statement) {
- statement_if_else = yy_element_stack[-1].children[0]
- if not isinstance(statement_if_else.children[0].type, t_def.TypeBool):
- statement_if_else.children[0] = t_def.add_cast(
- t_def.type_bool,
- statement_if_else.children[0]
- )
- }
- | %space (?E{t_def.StatementIf}IF '(' expression ')' statement) {
- statement_if = yy_element_stack[-1].children[0]
- if not isinstance(statement_if.children[0].type, t_def.TypeBool):
- statement_if.children[0] = t_def.add_cast(
- t_def.type_bool,
- statement_if.children[0]
- )
- }
- | %space (?E{t_def.StatementSwitch}SWITCH '(' expression ')' {
- expression = yy_element_stack[-4].children[0]
- assert isinstance(expression, t_def.Expression)
- assert isinstance(expression.type, t_def.TypeInt)
- switch_type.append(expression.type)
- } statement) {
- switch_type.pop()
- }
- | %space (?E{t_def.StatementWhile}WHILE '(' expression ')' statement) {
- statement_while = yy_element_stack[-1].children[0]
- if not isinstance(statement_while.children[0].type, t_def.TypeBool):
- statement_while.children[0] = t_def.add_cast(
- t_def.type_bool,
- statement_while.children[0]
- )
- }
- | %space (?E{t_def.StatementDoWhile}DO statement WHILE '(' expression ')' ';') {
- statement_do_while = yy_element_stack[-1].children[0]
- if not isinstance(statement_do_while.children[1].type, t_def.TypeBool):
- statement_do_while.children[1] = t_def.add_cast(
- t_def.type_bool,
- statement_do_while.children[1]
- )
- }
- | %space (?E{t_def.StatementFor}FOR '(' %space (?E{t_def.StatementExpression}expression_opt ';') expression_opt ';' expression_opt ')' statement) {
- statement_for = yy_element_stack[-1].children[0]
- statement_expression = statement_for.children[0]
- if not isinstance(statement_expression.children[0].type, t_def.TypeVoid):
- statement_expression.children[0] = t_def.add_cast(
- t_def.type_void,
- statement_expression.children[0]
- )
- if not isinstance(statement_for.children[1].type, t_def.TypeBool):
- statement_for.children[1] = t_def.add_cast(
- t_def.type_bool,
- statement_for.children[1]
- )
- if not isinstance(statement_for.children[2].type, t_def.TypeVoid):
- statement_for.children[2] = t_def.add_cast(
- t_def.type_void,
- statement_for.children[2]
- )
- }
- | %space (?E{t_def.StatementFor}FOR '(' declaration expression_opt ';' expression_opt ')' statement) {
- statement_for = yy_element_stack[-1].children[0]
- if not isinstance(statement_for.children[1].type, t_def.TypeBool):
- statement_for.children[1] = t_def.add_cast(
- t_def.type_bool,
- statement_for.children[1]
- )
- if not isinstance(statement_for.children[2].type, t_def.TypeVoid):
- statement_for.children[2] = t_def.add_cast(
- t_def.type_void,
- statement_for.children[2]
- )
- }
+ | %space (?E{t_def.StatementExpression}expression_opt ';')
+ | %space (?E{t_def.StatementIf}IF '(' expression ')' statement ELSE statement)
+ | %space (?E{t_def.StatementIf}IF '(' expression ')' statement)
+ | %space (?E{t_def.StatementSwitch}SWITCH '(' expression ')' statement)
+ | %space (?E{t_def.StatementWhile}WHILE '(' expression ')' statement)
+ | %space (?E{t_def.StatementDoWhile}DO statement WHILE '(' expression ')' ';')
+ | %space (?E{t_def.StatementFor}FOR '(' %space (?E{t_def.StatementExpression}expression_opt ';') expression_opt ';' expression_opt ')' statement)
+ | %space (?E{t_def.StatementFor}FOR '(' declaration expression_opt ';' expression_opt ')' statement)
| %space (?E{t_def.StatementGoto}GOTO identifier ';')
| %space (?E{t_def.StatementContinue}CONTINUE ';')
| %space (?E{t_def.StatementBreak}BREAK ';')
- | %space (?E{t_def.StatementReturn}RETURN expression_opt ';') {
- statement_return = yy_element_stack[-1].children[0]
- if statement_return.children[0].type != return_type:
- statement_return.children[0] = t_def.add_cast(
- return_type,
- statement_return.children[0]
- )
- }
+ | %space (?E{t_def.StatementReturn}RETURN expression_opt ';')
;
block_item_list_opt
function_definition
: %space (?E{t_def.FunctionDefinition}declaration_specifier_list1 declarator %space (?E{t_def.DeclarationList}declaration_list_opt) '{' {
- global scope, _base_type, storage_class, return_type
-
- # add function definition to the outer scope
-
- # we refer to the global variables for _base_type and storage_class
- declarator = yy_element_stack[-6].children[0]
- name, _type = declarator.get_name_and_type(_base_type)
- #print('func', name)
-
- assert isinstance(_type, t_def.TypeFunction)
- assert storage_class in {
- t_def.STORAGE_CLASS_NONE,
- t_def.STORAGE_CLASS_EXTERN,
- t_def.STORAGE_CLASS_STATIC
- }
-
- if name in scope.identifiers:
- scope_identifier = scope.identifiers[name]
- assert scope_identifier.type == _type
- else:
- scope_identifier = t_def.Scope.Identifier(
- name = name,
- type = _type,
- storage_class = t_def.STORAGE_CLASS_NONE
- )
- scope.identifiers[name] = scope_identifier
- $$ = scope_identifier # for FunctionDefinition when constructed
-
- assert not scope_identifier.defined
- scope_identifier.defined = True
-
- if storage_class == t_def.STORAGE_CLASS_NONE:
- pass
- elif scope_identifier.storage_class == t_def.STORAGE_CLASS_NONE:
- scope_identifier.storage_class = storage_class
- else:
- assert scope_identifier.storage_class == storage_class
-
- # now create the inner scope and add formal parameters
-
- scope = t_def.Scope(enclosing_scope = scope)
-
- declarator_function = t_def.get_declarator_function(declarator)
- assert declarator_function is not None
- if isinstance(declarator_function, t_def.DeclaratorFunctionANSI):
- parameter_declarations = declarator_function.children[1].children
- if (
- len(parameter_declarations) != 1 or
- len(parameter_declarations[0].name) or
- not isinstance(parameter_declarations[0].type, t_def.TypeVoid)
- ):
- for i in parameter_declarations:
- name = i.name
- _type = t_def.array_decay(i.type)
- #print('param', name)
-
- assert name not in scope.identifiers
- scope_identifier = t_def.Scope.Identifier(
- name = name,
- type = _type,
- storage_class = t_def.STORAGE_CLASS_AUTO,
- defined = True
- )
- scope.identifiers[name] = scope_identifier
- i.scope_identifier = scope_identifier
-
- assert _type.size >= 0 # must be of determinate size
- align_m1 = _type.align - 1
- scope.size = (scope.size + align_m1) & ~align_m1
- scope_identifier.offset = scope.size
- scope.size += _type.size
- elif isinstance(declarator_function, t_def.DeclaratorFunctionKAndR):
- # has no information about formal parameter types, ignore for now
- pass
- else:
- assert False
-
- # these globals were needed whilst parsing the header of the function
- _base_type = None
- storage_class = -1
-
- # this global is needed for parsing the body of the function
- return_type = $$.type.return_type
-
- # new way
global doing_typedef
# this global is set by declaration_specifier_list1 if doing typedef,
# it needs to be cleared as soon as we finish all of the declarators
+ # POSSIBLE BUG: SHOULDN T IT BE CLEARED BEFORE THE DECLARATION LIST?
doing_typedef = False
- # new way
typedef_stack.append(set())
} %space (?E{t_def.BlockItemList}block_item_list_opt) '}') {
- global scope, return_type
-
- function_definition = yy_element_stack[-1].children[0]
- function_definition.scope_identifier = $5
-
- function_definition.children[3].scope = scope
- scope = scope.enclosing_scope
-
- # this global was needed for parsing the body of the function
- return_type = None
-
- # new way
typedef_stack.pop()
}
;
print(f'{in_file:s}({loc.first_line:d},{loc.first_column:d}..{loc.last_line:d},{loc.last_column:d}): {msg:s}')
sys.exit(1)
-# helper factory to construct Expression object and analyze type and value
-def build(factory, *args, **kwargs):
- expression = factory(*args, **kwargs)
- expression.calc_type()
- expression.calc_value()
- return expression
-
# intercept calls to yylex() for typedef processing
no_typedef_tokens = {ord('.'), PTR_OP, STRUCT, UNION, ENUM}
def yylex_typedef():
token = lex_yy.yylex()
if token == IDENTIFIER and last_token not in no_typedef_tokens:
- i = scope
- while i is not None:
- if lex_yy.yytext in i.identifiers:
- scope_identifier = i.identifiers[lex_yy.yytext]
- if scope_identifier.storage_class == t_def.STORAGE_CLASS_TYPEDEF:
- token = TYPEDEF_NAME
- yylval = scope_identifier
- break
- i = i.enclosing_scope
-
- # new way (just for testing at the moment)
for i in range(len(typedef_stack) - 1, -1, -1):
if lex_yy.yytext in typedef_stack[i]:
- assert token == TYPEDEF_NAME
+ token = TYPEDEF_NAME
break
- else:
- assert token != TYPEDEF_NAME
last_token = token
return token