Compiler Overview

The Jancy compiler uses a lexical analyzer generated by Ragel (a universal finite state machine compiler). It is perfectly suited for building lexers due to the convenience and expressiveness of its input language and, even more importantly, the unbeatable performance of the output code.

On the backend, Jancy uses LLVM, which offers a reliable optimizer and native code generator for a wide variety of platforms. LLVM also significantly simplifies the process of ensuring ABI compatibility with C/C++.

As for the syntax analyzer we use our own wheel generator of table-driven top-down LL parsers called Graco. Read the Graco page for some thoughts on why we settled on this approach.

The output of the parser is LLVM IR without intermediate generation of an AST: Unlike with bottom-up parsers, in top-down parsers it is rather convenient to perform semantic analysis and generate IR in parallel while parsing, i.e. while the parser is matching the grammar rules.

Jancy grammar belongs to context-sensitive LL(2).

Syntactic/semantic analysis is performed in multiple passes (mostly two, with some rules requiring three passes). This, however, does not mean that the source is re-tokenized multiple times. The second pass is needed to allow the usage of global entities (namespaces, types, variables, functions and properties) before their declaration, which might be "below" or even reside in a separate compilation unit. The third pass is necessary for the preliminary calculation of reactor class layouts.

Graco — LL Grammar Compiler

The parser for the Jancy compiler is generated using Grammar, our in-house builder of table-driven LL parsers.

The main reason why we chose a generated parser while most production-level compilers favor recursive descent is this: we wanted to achieve the perfect syntax for our language. In order to succeed we had to go through a lot of trial and error experiments. We didn't want to be bogged down in the routine of adjusting a recursive-descent parser. In addition, the generated parser provides two more benefits:

  • EBNF grammar as a permanently relevant syntax reference
  • Natural constraints to not let us get too crazy with the syntax.

What's wrong with ANTLR, Coco, Yacc/Bison, Lemon and other undoubtedly respectable and tried-and-true parser generators is in itself an interesting subject. It is, however, the one for a separate article, as it would require detailed comparison with lots of code snippets. We will get to that some day. For now let's just say that we needed a top-down parser generator with predictable and configurable conflict resolution mechanism and we found that each existing parser generator couldn't quite cut it at one situation or another.

The collaboration model between the parser and the lexer was "lifted" from Lemon. The Graco-generated parser does not call the lexer. Instead, the external loop asks the lexer to tokenize the next source chunk and feeds tokens into the table-driven parser. This model allows for an incremental parsing of incomplete compilation units (supports pause-and-resume, so to speak). Plus there is no need for artificial nesting level limitations due to the danger of a stack overflow (it's simply not an issue here).

Jancy Grammar

Below you can check the full Jancy grammar for reference. This listing is auto-generated from *.llk files by Graco parser generator, and is basically the actual Jancy grammar as it is used by the Jancy compiler but with all the actions, rule attributes and rule arguments removed for readability.

lookahead = 2;

start
nullable
compilation_unit
    :   global_declaration*
    ;

global_declaration
    :   import_declaration
    |   namespace_declaration
    |   extension_declaration
    |   using_declaration
    |   friend_declaration
    |   access_declaration
    |   alignment_declaration
    |   normal_item_declaration
    |   named_type_specifier
    |   ';'
    ;

import_declaration
    :   TokenKind_Import TokenKind_Literal
    ;

namespace_declaration
    :   TokenKind_Namespace qualified_name '{' global_declaration* '}'
    ;

extension_declaration
    :   TokenKind_Extension TokenKind_Identifier ':' type_name '{' named_type_block_declaration* '}'
    ;

using_declaration
    :   TokenKind_Using using_namespace_kind qualified_name_list ';'
    ;

friend_declaration
    :   TokenKind_Friend qualified_name_list ';'
    ;

access_declaration
    :   access_specifier ':'
    ;

alignment_declaration
    :   TokenKind_Alignment '='? alignment_value ';'
    |   TokenKind_Alignment '(' alignment_value ')'
    ;

start
normal_item_declaration
    :   item_declaration_w_specifier
    |   item_declaration_wo_specifier
    ;

named_type_specifier
    :   enum_specifier
    |   struct_specifier
    |   union_specifier
    |   class_specifier
    |   library_specifier
    ;

named_type_block_declaration
    :   friend_declaration
    |   access_declaration
    |   alignment_declaration
    |   setas_declaration
    |   normal_item_declaration
    |   named_type_specifier
    |   ';'
    ;

setas_declaration
    :   TokenKind_SetAs '='? type_name ';'
    |   TokenKind_SetAs '(' type_name ')'
    ;

local_declaration
    :   statement
    |   using_declaration
    |   alignment_declaration
    |   local_item_declaration
    |   named_type_specifier
    |   catch_label
    |   finally_label
    ;

statement
    :   compound_stmt
    |   expression_stmt
    |   if_stmt
    |   switch_stmt
    |   while_stmt
    |   do_stmt
    |   for_stmt
    |   break_stmt
    |   continue_stmt
    |   return_stmt
    |   once_stmt
    |   try_stmt
    |   unsafe_stmt
    |   assert_stmt
    |   ';'
    ;

local_item_declaration
    :   item_declaration_w_specifier
    |   item_declaration_wo_specifier
    ;

catch_label
    :   TokenKind_Catch ':'
    ;

finally_label
    :   TokenKind_Finally ':'
    ;

qualified_name
    :   qualified_name_impl
    ;

type_name
    :   type_name_impl
    ;

using_namespace_kind
    :   TokenKind_Namespace
    |   TokenKind_Extension
    ;

qualified_name_list
    :   qualified_name (',' qualified_name)*
    ;

access_specifier
    :   TokenKind_Public
    |   TokenKind_Protected
    ;

alignment_value
    :   TokenKind_Integer
    |   TokenKind_Default
    ;

setas_value
    :   type_name
    |   TokenKind_Default
    ;

qualified_name_impl
    :   TokenKind_Identifier ('.' TokenKind_Identifier)*
    ;

item_declaration_w_specifier
    :   declaration_specifier_list declarator_list? declaration_terminator
    ;

item_declaration_wo_specifier_rslv
    :   declarator_name '('
    ;

item_declaration_wo_specifier
    :   declarator_prefix* declarator_name function_suffix declarator_suffix* declaration_terminator
    ;

declaration_specifier_list
    :   declaration_specifier+
    ;

declarator_list
    :   full_declarator (',' full_declarator)*
    ;

declaration_terminator
    :   ';'
    |   declaration_body_pass1
    ;

declarator_prefix
    :   '*' type_modifier*
    ;

declarator_name
    :   declarator_qualifier ('.' declarator_qualifier)*
    ;

function_suffix
    :   '(' function_formal_argument_list? ')' function_modifier*
    ;

declarator_suffix
    :   array_suffix
    |   function_suffix
    |   bitfield_suffix
    ;

declaration_body_pass1
    :   compound_stmt_pass1
    ;

compound_stmt_pass1
    :   '{' statement_pass1* '}'
    ;

statement_pass1
    :   compound_stmt_pass1
    |   TokenKind_Catch
    |   TokenKind_Finally
    |   any
    ;

type_name_impl
    :   type_specifier_modifier_list declarator_prefix* declarator_suffix*
    ;

type_specifier_modifier_list
    :   type_specifier_modifier+
    ;

type_name_list
    :   type_name (',' type_name)*
    ;

attribute_block
    :   '[' attribute_declarator_list ']'
    ;

nullable
attribute_declarator_list
    :   attribute_declarator (',' attribute_declarator)*
    ;

nullable
attribute_declarator
    :   TokenKind_Identifier ('=' expression_pass1)?
    |   epsilon
    ;

expression_pass1
    :   primary_expr_pass1+
    ;

primary_expr_pass1
    :   '{' primary_expr_pass1* '}'
    |   '[' primary_expr_pass1* ']'
    |   '(' primary_expr_pass1* ')'
    |   any
    ;

arg_list_pass1
    :   '(' arg_pass1* ')'
    ;

arg_pass1
    :   '(' arg_pass1* ')'
    |   any
    ;

start
expression_save_value
    :   expression
    ;

start
expression
    :   conditional_expr
    ;

start
nullable
expression_or_empty_list_save_list
    :   expression_or_empty_list
    ;

nullable
expression_or_empty_list
    :   expression (',' expression_or_empty)*
    |   ',' expression_or_empty (',' expression_or_empty)*
    |   epsilon
    ;

conditional_expr
    :   logical_or_expr ('?' conditional_expr ':' conditional_expr)?
    ;

nullable
expression_or_empty
    :   conditional_expr
    |   epsilon
    ;

expression_list
    :   expression (',' expression)*
    ;

start
constant_expr
    :   conditional_expr
    ;

start
constant_integer_expr
    :   expression
    ;

logical_or_expr
    :   logical_and_expr (TokenKind_LogOr logical_and_expr)*
    ;

logical_and_expr
    :   inclusive_or_expr (TokenKind_LogAnd inclusive_or_expr)*
    ;

inclusive_or_expr
    :   exclusive_or_expr ('|' exclusive_or_expr)*
    ;

exclusive_or_expr
    :   and_expr ('^' and_expr)*
    ;

and_expr
    :   equality_expr ('&' equality_expr)*
    ;

equality_expr
    :   relational_expr (equality_operator relational_expr)*
    ;

relational_expr
    :   shift_expr (relational_operator shift_expr)*
    ;

equality_operator
    :   TokenKind_Eq
    |   TokenKind_Ne
    ;

shift_expr
    :   additive_expr (shift_operator additive_expr)*
    ;

relational_operator
    :   '<'
    |   '>'
    |   TokenKind_Le
    |   TokenKind_Ge
    ;

additive_expr
    :   multiplicative_expr (additive_operator multiplicative_expr)*
    ;

shift_operator
    :   TokenKind_Shl
    |   TokenKind_Shr
    ;

multiplicative_expr
    :   at_expr (multiplicative_operator at_expr)*
    ;

additive_operator
    :   '+'
    |   '-'
    ;

at_expr
    :   assignment_expr ('@' assignment_expr)*
    ;

multiplicative_operator
    :   '*'
    |   '/'
    |   '%'
    ;

assignment_expr
    :   unary_expr assignment_operator_expr?
    ;

unary_expr
    :   postfix_expr
    |   unary_operator_expr
    ;

assignment_operator_expr
    :   assignment_operator conditional_expr
    |   '=' curly_initializer
    ;

assignment_operator
    :   '='
    |   TokenKind_RefAssign
    |   TokenKind_AddAssign
    |   TokenKind_SubAssign
    |   TokenKind_MulAssign
    |   TokenKind_DivAssign
    |   TokenKind_ModAssign
    |   TokenKind_ShlAssign
    |   TokenKind_ShrAssign
    |   TokenKind_AndAssign
    |   TokenKind_XorAssign
    |   TokenKind_OrAssign
    ;

start
curly_initializer
    :   '{' curly_initializer_item (',' curly_initializer_item)* '}'
    ;

postfix_expr
    :   primary_expr postfix_operator*
    ;

unary_operator_expr
    :   '+' unary_expr
    |   '-' unary_expr
    |   '~' unary_expr
    |   '&' unary_expr
    |   '*' unary_expr
    |   '!' unary_expr
    |   TokenKind_Inc unary_expr
    |   TokenKind_Dec unary_expr
    |   TokenKind_Try unary_expr
    |   TokenKind_Dynamic? '(' type_name ')' unary_expr
    |   TokenKind_New new_operator_type new_operator_curly_initializer?
    |   TokenKind_Delete unary_expr
    ;

cast_operator_rslv
    :   TokenKind_Dynamic? '(' type_specifier_modifier
    ;

new_operator_type
    :   type_name_impl
    |   qualified_type_name TokenKind_Construct? '(' expression_or_empty_list ')'
    ;

new_operator_curly_initializer
    :   curly_initializer
    ;

type_name_w_constructor_rslv
    :   qualified_name TokenKind_Construct? '('
    ;

qualified_type_name
    :   basetype_qualified_name
    ;

type_specifier_modifier
    :   type_specifier
    |   type_modifier
    ;

primary_expr
    :   '(' conditional_expr ')'
    |   literal
    |   TokenKind_BaseType
    |   TokenKind_Identifier
    |   TokenKind_This
    |   TokenKind_Integer
    |   TokenKind_Fp
    |   TokenKind_True
    |   TokenKind_False
    |   TokenKind_Null
    |   TokenKind_Dynamic? TokenKind_SizeOf '(' type_name_or_expr ')'
    |   TokenKind_Dynamic? TokenKind_CountOf '(' type_name_or_expr ')'
    |   TokenKind_Dynamic? TokenKind_TypeOf '(' type_name_or_expr ')'
    |   TokenKind_OffsetOf '(' expression_0 ')'
    |   TokenKind_BindingOf '(' conditional_expr ')'
    ;

postfix_operator
    :   '(' expression_or_empty_list ')'
    |   '~' '(' expression_or_empty_list ')'
    |   '[' expression_or_empty ']'
    |   TokenKind_Inc
    |   TokenKind_Dec
    |   '.' TokenKind_Weak? member_operator
    |   TokenKind_Ptr member_operator
    ;

member_operator
    :   TokenKind_Identifier
    |   TokenKind_Get
    |   TokenKind_Set
    ;

literal
    :   literal_atom+
    ;

type_name_or_expr
    :   type_name
    |   expression
    ;

start
expression_0
    :   conditional_expr_0
    ;

literal_atom
    :   TokenKind_Literal
    |   TokenKind_HexLiteral
    |   TokenKind_FmtLiteral expression TokenKind_FmtSpecifier?
    ;

nullable
curly_initializer_item
    :   TokenKind_Identifier '=' (curly_initializer | expression)
    |   expression
    |   curly_initializer
    |   epsilon
    ;

start
expression_save_value_0
    :   expression_0
    ;

conditional_expr_0
    :   logical_or_expr_0 ('?' conditional_expr_0 ':' conditional_expr_0)?
    ;

nullable
expression_or_empty_0
    :   conditional_expr_0
    |   epsilon
    ;

expression_list_0
    :   expression_0 (',' expression_0)*
    ;

nullable
expression_or_empty_list_0
    :   expression_0 (',' expression_or_empty_0)*
    |   ',' expression_or_empty_0 (',' expression_or_empty_0)*
    |   epsilon
    ;

logical_or_expr_0
    :   logical_and_expr_0 (TokenKind_LogOr logical_and_expr_0)*
    ;

logical_and_expr_0
    :   inclusive_or_expr_0 (TokenKind_LogAnd inclusive_or_expr_0)*
    ;

inclusive_or_expr_0
    :   exclusive_or_expr_0 ('|' exclusive_or_expr_0)*
    ;

exclusive_or_expr_0
    :   and_expr_0 ('^' and_expr_0)*
    ;

and_expr_0
    :   equality_expr_0 ('&' equality_expr_0)*
    ;

equality_expr_0
    :   relational_expr_0 (equality_operator relational_expr_0)*
    ;

relational_expr_0
    :   shift_expr_0 (relational_operator shift_expr_0)*
    ;

shift_expr_0
    :   additive_expr_0 (shift_operator additive_expr_0)*
    ;

additive_expr_0
    :   multiplicative_expr_0 (additive_operator multiplicative_expr_0)*
    ;

multiplicative_expr_0
    :   at_expr_0 (multiplicative_operator at_expr_0)*
    ;

at_expr_0
    :   assignment_expr_0 ('@' assignment_expr_0)*
    ;

assignment_expr_0
    :   unary_expr_0 (assignment_operator conditional_expr_0)?
    ;

unary_expr_0
    :   postfix_expr_0
    |   unary_operator_expr_0
    ;

postfix_expr_0
    :   primary_expr_0 postfix_operator_0*
    ;

unary_operator_expr_0
    :   '+' unary_expr_0
    |   '-' unary_expr_0
    |   '~' unary_expr_0
    |   '&' unary_expr_0
    |   '*' unary_expr_0
    |   '!' unary_expr_0
    |   TokenKind_Inc unary_expr_0
    |   TokenKind_Dec unary_expr_0
    |   TokenKind_Try unary_expr_0
    |   '(' type_name ')' unary_expr_0
    |   storage_specifier? TokenKind_New new_operator_sype_0
    |   TokenKind_Delete unary_expr_0
    ;

storage_specifier
    :   TokenKind_Typedef
    |   TokenKind_Alias
    |   TokenKind_Static
    |   TokenKind_Thread
    |   TokenKind_Stack
    |   TokenKind_Heap
    |   TokenKind_Abstract
    |   TokenKind_Virtual
    |   TokenKind_Override
    |   TokenKind_Mutable
    ;

new_operator_sype_0
    :   type_name
    |   qualified_type_name TokenKind_Construct? '(' expression_or_empty_list_0 ')'
    ;

primary_expr_0
    :   '(' conditional_expr_0 ')'
    |   literal_0
    |   TokenKind_BaseType
    |   TokenKind_Identifier
    |   TokenKind_This
    |   TokenKind_Integer
    |   TokenKind_Fp
    |   TokenKind_True
    |   TokenKind_False
    |   TokenKind_Null
    |   TokenKind_Dynamic? TokenKind_SizeOf '(' type_name_or_expr_0 ')'
    |   TokenKind_Dynamic? TokenKind_CountOf '(' type_name_or_expr_0 ')'
    |   TokenKind_Dynamic? TokenKind_TypeOf '(' type_name_or_expr_0 ')'
    |   TokenKind_OffsetOf '(' expression_0 ')'
    |   TokenKind_BindingOf '(' conditional_expr_0 ')'
    ;

postfix_operator_0
    :   '(' expression_or_empty_list_0 ')'
    |   '~' '(' expression_or_empty_list_0 ')'
    |   '[' expression_or_empty_0 ']'
    |   TokenKind_Inc
    |   TokenKind_Dec
    |   '.' TokenKind_Weak? member_operator_0
    |   TokenKind_Ptr member_operator_0
    ;

member_operator_0
    :   TokenKind_Identifier
    |   TokenKind_Get
    |   TokenKind_Set
    ;

literal_0
    :   literal_atom_0+
    ;

type_name_or_expr_0
    :   type_name
    |   expression_0
    ;

literal_atom_0
    :   TokenKind_Literal
    |   TokenKind_HexLiteral
    |   TokenKind_FmtLiteral expression_0 TokenKind_FmtSpecifier?
    ;

start
compound_stmt
    :   '{' local_declaration* '}'
    ;

start
automaton_compound_stmt
    :   '{' automaton_declaration* '}'
    ;

automaton_declaration
    :   TokenKind_RegExpLiteral
    |   local_declaration local_declaration*
    ;

start
constructor_compound_stmt
    :   '{' btm_construct_stmt* local_declaration* '}'
    ;

btm_construct_stmt
    :   btm_construct_name '(' expression_or_empty_list ')'
    |   TokenKind_BaseType '.' TokenKind_Construct '(' expression_or_empty_list ')'
    |   ';'
    ;

btm_construct_stmt_rslv
    :   TokenKind_Identifier '.' (TokenKind_Identifier '.')* TokenKind_Construct
    ;

btm_construct_name
    :   TokenKind_Identifier '.' (TokenKind_Identifier '.')* TokenKind_Construct
    ;

expression_stmt
    :   expression ';'
    ;

if_stmt
    :   TokenKind_If '(' expression ')' statement (TokenKind_Else statement)?
    ;

switch_stmt
    :   TokenKind_Switch '(' expression ')' '{' switch_block_stmt* '}'
    ;

while_stmt
    :   TokenKind_While '(' expression ')' statement
    ;

do_stmt
    :   TokenKind_Do statement TokenKind_While '(' expression ')' ';'
    ;

for_stmt
    :   TokenKind_For '(' (local_item_declaration | expression_or_empty_list ';') for_stmt_condition ';' expression_list? ')' statement
    ;

break_stmt
    :   TokenKind_Break ';'
    ;

continue_stmt
    :   TokenKind_Continue ';'
    ;

return_stmt
    :   TokenKind_Return expression? ';'
    ;

once_stmt
    :   storage_specifier? TokenKind_Once statement
    ;

try_stmt
    :   TokenKind_Try '{' local_declaration* '}'
    ;

unsafe_stmt
    :   TokenKind_Unsafe '{' local_declaration* '}'
    ;

assert_stmt
    :   TokenKind_Assert '(' expression_pass1 (',' expression)? ')'
    ;

switch_block_stmt
    :   TokenKind_Case constant_integer_expr ':'
    |   TokenKind_Default ':'
    |   local_declaration
    ;

nullable
for_stmt_condition
    :   expression
    |   epsilon
    ;

start
reactor_body
    :   '{' reactor_stmt reactor_stmt* '}'
    ;

reactor_stmt
    :   reactor_expression_stmt
    |   reactor_onevent_stmt
    |   ';'
    ;

reactor_expression_stmt
    :   expression_pass1 ';'
    ;

reactor_onevent_stmt
    :   TokenKind_OnEvent reactor_event_name function_suffix compound_stmt
    ;

reactor_event_name
    :   '(' expression_list ')'
    |   TokenKind_BindingOf '(' expression ')'
    |   any+
    ;

start
reactor_body_0
    :   '{' reactor_stmt_0 reactor_stmt_0* '}'
    ;

reactor_stmt_0
    :   reactor_expression_stmt_0
    |   reactor_onevent_stmt_0
    |   ';'
    ;

reactor_expression_stmt_0
    :   expression_0 ';'
    ;

reactor_onevent_stmt_0
    :   TokenKind_OnEvent reactor_event_name_0 function_suffix reactor_compound_stmt_0
    ;

reactor_event_name_0
    :   '(' expression_list_0 ')'
    |   TokenKind_BindingOf '(' expression_0 ')'
    |   any+
    ;

reactor_compound_stmt_0
    :   '{' (reactor_compound_stmt_0 | any)* '}'
    ;

declaration_specifier
    :   attribute_block
    |   storage_specifier
    |   access_specifier
    |   type_specifier
    |   type_modifier
    ;

type_specifier
    :   TokenKind_Void
    |   TokenKind_Variant
    |   TokenKind_Class
    |   TokenKind_Bool
    |   TokenKind_Int8
    |   TokenKind_Int16
    |   TokenKind_Int32
    |   TokenKind_Int64
    |   TokenKind_Int
    |   TokenKind_IntPtr
    |   TokenKind_Char
    |   TokenKind_Float
    |   TokenKind_Double
    |   TokenKind_Auto
    |   property_template_specifier
    |   qualified_type_name
    ;

type_modifier
    :   TokenKind_Unsigned
    |   TokenKind_BigEndian
    |   TokenKind_Const
    |   TokenKind_ReadOnly
    |   TokenKind_Volatile
    |   TokenKind_Weak
    |   TokenKind_Thin
    |   TokenKind_Safe
    |   TokenKind_Unsafe
    |   TokenKind_Cdecl
    |   TokenKind_Stdcall
    |   TokenKind_Thiscall
    |   TokenKind_Jnccall
    |   TokenKind_Array
    |   TokenKind_Function
    |   TokenKind_Property
    |   TokenKind_Bindable
    |   TokenKind_AutoGet
    |   TokenKind_Indexed
    |   TokenKind_Multicast
    |   TokenKind_Event
    |   TokenKind_Reactor
    |   TokenKind_Automaton
    ;

property_template_specifier
    :   TokenKind_Property named_type_block_impl
    ;

qualified_type_name_rslv
    :   basetype_qualified_name '('?
    ;

basetype_qualified_name
    :   TokenKind_BaseType
    |   TokenKind_BaseType '.' qualified_name_impl
    |   qualified_name_impl
    ;

start
named_type_block_impl
    :   '{' named_type_block_declaration* '}'
    ;

full_declarator
    :   declarator (TokenKind_Construct? arg_list_pass1)? ('=' expression_pass1)?
    ;

declarator
    :   declarator_prefix* declarator_name declarator_suffix*
    ;

declarator_qualifier
    :   TokenKind_Identifier
    |   TokenKind_Get
    |   TokenKind_Set
    |   TokenKind_Preconstruct
    |   TokenKind_Construct
    |   TokenKind_Destruct
    |   TokenKind_Static TokenKind_Construct
    |   TokenKind_Static TokenKind_Destruct
    |   TokenKind_Operator declarator_operator_qualifier
    ;

declarator_operator_qualifier
    :   '(' ')'
    |   type_name
    |   operator_name
    |   TokenKind_New
    |   TokenKind_Ellipsis
    |   TokenKind_Cdecl TokenKind_Ellipsis
    ;

operator_name
    :   '~'
    |   '!'
    |   TokenKind_Inc
    |   TokenKind_Dec
    |   TokenKind_Postfix TokenKind_Inc
    |   TokenKind_Postfix TokenKind_Dec
    |   TokenKind_Postfix? TokenKind_Ptr
    |   '+'
    |   '-'
    |   '*'
    |   '/'
    |   '%'
    |   TokenKind_Shl
    |   TokenKind_Shr
    |   '&'
    |   '^'
    |   '|'
    |   TokenKind_Eq
    |   TokenKind_Ne
    |   '<'
    |   TokenKind_Le
    |   '>'
    |   TokenKind_Ge
    |   '='
    |   TokenKind_RefAssign
    |   TokenKind_AddAssign
    |   TokenKind_SubAssign
    |   TokenKind_MulAssign
    |   TokenKind_DivAssign
    |   TokenKind_ModAssign
    |   TokenKind_ShlAssign
    |   TokenKind_ShrAssign
    |   TokenKind_AndAssign
    |   TokenKind_XorAssign
    |   TokenKind_OrAssign
    |   TokenKind_AtAssign
    |   TokenKind_LogAnd
    |   TokenKind_LogOr
    |   '[' ']'
    |   '@'
    ;

array_suffix
    :   '[' expression_pass1 ']'
    |   '[' TokenKind_Integer ']'
    |   '[' ']'
    ;

function_suffix_rslv
    :   '(' ')'
    |   '(' TokenKind_Ellipsis ')'
    |   '(' (type_specifier | type_modifier)
    ;

bitfield_suffix
    :   ':' TokenKind_Integer
    ;

function_formal_argument_list
    :   function_formal_argument (',' function_formal_argument)*
    ;

function_modifier
    :   TokenKind_Throws
    |   TokenKind_Const
    ;

function_formal_argument
    :   declaration_specifier_list declarator_prefix* declarator_name? declarator_suffix* ('=' expression_pass1)?
    |   TokenKind_Ellipsis
    ;

enum_specifier
    :   enum_modifier* TokenKind_Enum TokenKind_Identifier? (':' type_name)? enum_block
    ;

struct_specifier
    :   TokenKind_Struct TokenKind_Identifier? (':' type_name_list)? named_type_block
    ;

union_specifier
    :   TokenKind_Union TokenKind_Identifier? named_type_block
    ;

class_specifier
    :   TokenKind_Opaque? TokenKind_Class TokenKind_Identifier (':' type_name_list)? named_type_block
    ;

library_specifier
    :   TokenKind_Library TokenKind_Identifier '{' named_type_block_declaration* '}'
    ;

start
named_type_specifier_save_type
    :   named_type_specifier
    ;

enum_modifier
    :   TokenKind_Exposed
    |   TokenKind_BitFlag
    ;

enum_block
    :   '{' enum_member_list '}'
    ;

nullable
enum_member_list
    :   enum_member (',' enum_member)*
    ;

nullable
enum_member
    :   TokenKind_Identifier ('=' expression_pass1)?
    |   epsilon
    ;

named_type_block
    :   named_type_block_impl
    ;

Controllers

DS110x Family

Boards

EM1001