-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgrammar.ebnf
147 lines (123 loc) · 6.44 KB
/
grammar.ebnf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
(* Important:
This grammar is mostly representative of what is implemented but
not all
*)
(* Notes:
In character categories and literals, whitespace must be absent.
In all other rules whitespace is ignored.
*)
(* Character categories *)
hex_digit = "0" ;.. "9" | "A" ;.. "F" | "a" ;.. "f" ;
octal_digit = "0" ;.. "7" ;
decimal_digit = "0" ;.. "9" ;
text_character = ? space, tab, or any Unicode character greater than U+0020 ? ;
ascii_letter = "A" ;.. "F" | "a" ;.. "f" ;
ascii_alphanum = ascii_letter | decimal_digit ;
character = text_character | newline | carriage_return ;
(* Literals *)
identifier = ascii_letter , { [ "_" ] ascii_alphanum } ;
scoped_identifier = [ identifier , "." ] , identifier ;
hex_literal = "0" , ( "x" ) , { hex_digit } ;
octal_literal = "0" , { octal_digit } ;
decimal_literal = ( "1" , "9" ) , { decimal_digit } ;
mantissa = "0" | decimal_literal ;
decimals = decimal_digit , { decimal_digit } ;
exponent = ( "e" ) , [ "+" | "-" ] , decimals ;
integer_literal = hex_literal | decimal_literal | octal_literal ;
float_literal = mantissa , "." , [ decimals ] , [ exponent ]
| mantissa , exponent
| "." , decimals | [ exponent ] ;
number_literal = integer_literal | float_literal ;
text_literal = '"' , { text_character } , '"' ;
infix_name = "_" , { ascii_letter | decimal_digit } , "_" ;
prefix_name = { ascii_letter | decimal_digit } , "_" ;
postfix_name = "_" , { ascii_letter | decimal_digit } ;
math_symbol = "+", "-", "*", "/", "%" ;
operator = math_symbol | infix_name | prefix_name | postfix_name ;
directive = "#" , identifier ;
(* Types *)
named_type = scoped_identifier ;
array_type = "[" , [ ".." | number_literal ] , "]" , type ;
pointer_type = "^" , type ;
function_type = "(" , [ type , { "," , type } ] , ")" , [ "->" , type ] ;
type = array_type | function_type | named_type | pointer_type ;
(* Statements *)
done_stmt = "done" , ";" ;
return_stmt = "return" , expr , ";" ;
assignment = expr_list , [ operator ] , "=" , expr_list ;
assign_stmt = assignment , ";" ;
expr_range = infix_expr , ".." , infix_expr ;
each_range = identifier , [ "," , identifier ] , "in" , ( infix_expr | expr_range ) ;
for_range = mutable_decl , expr , ";" , assignment ;
for_stmt = "for" , ( for_range | each_range ) , assignment ;
while_stmt = "while" , expr , block ;
if_stmt = "if" , expr , block , { "else" , "if" , expr , block } , [ "else" , block ] ;
stmt = expr , ";" | if_stmt | for_stmt | while_stmt | assign_stmt | done_stmt | return_stmt ;
short_block = ":" , stmt ;
long_block = { directive } , "{" , { stmt | decl | long_block } , "}" ;
block = short_block | long_block ;
(* Expressions *)
function_param = identifier , ":" , type
function_expr = "(" , [ function_param , { "," , function_param } ] , ")" , ( short_block | [ "->" , type ] , long_block ) ;
group_expr = "(" , expr , ")";
value_expr = identifier | text_literal | number_literal ;
base_expr = value_expr | group_expr | function_expr ;
call_syntax = "(" , [ expr , { "," , expr } ] , ")" ;
postfix_expr = base_expr , { operator | call_syntax | "[" expr "]" | "." identifier } ;
prefix_expr = { operator | "~" | "^" } , postfix_expr ;
infix_expr = prefix_expr , { operator , infix_expr } ;
includes_expr = infix_expr , [ "not" ] , "in" , infix_expr ;
greater_expr = { ( ">=" | ">" ) , infix_expr } ;
lesser_expr = { ( "<=" | "<" ) , infix_expr } ;
equality_expr = { "==" , infix_expr } ;
identity_expr = { "is" , infix_expr } ;
compare_expr = infix_expr , [ identity_expr | equality_expr | lesser_expr | greater_expr | includes_expr ] ;
logic_expr = compare_expr , { ( "and" | "or" ) compare_expr } ;
expr = logic_expr ;
expr_list = expr { "," expr } ;
(* Notes:
Above is the unambiguous non-left-recurive grammar for expressions which
can be used to verify that a given sentence matches the expression grammar
with an LL(2) or recursive descent parser.
Sadly, concrete grammars are harder to read for humans, so below
are simpler rules intended for human consumption.
subscript_expr = expr , "[" expr "]" ;
member_expr = expr , "." , identifier ;
call_expr = expr , { "(" , [ expr , { "," , expr } ] , ")" } ;
indirect_expr = "~" , expr ;
address_expr = "^" , expr ;
postfix_expr = expr , operator ;
prefix_expr = operator , expr ;
infix_expr = expr , ( operator ) , expr ;
normal_expr = value_expr | group_expr | function_expr | member_expr | call_expr
| indirect_expr | address_expr | prefix_expr | postfix_expr | infix_expr ;
The grammar for comparison expressions in philomath is somewhat unusual
compared to other languages in that it allows expression of comparisons in
a more math-friendly style. Here are a few examples:
a == b == c is equivalent to (a == b) and (b == c) and (a == c)
a < b <= c is equivalent to (a < b) and (b <= c) and (a < c)
In most cases the last comparison can be optimized away, however it is
important when describing the behavior of inequality expressions:
(can't decide on the best operator; "<>", "!=", "=/=", etc)
a <> b <> c is equivalent to (a <> b) and (b <> c) and (a <> c)
greater_expr = normal_expr , { ( ">=" | ">" ) , normal_expr } ;
lesser_expr = normal_expr , { ( "<=" | "<" ) , normal_expr } ;
notequal_expr = normal_expr , { "!=" , normal_expr } ;
equality_expr = normal_expr , { "==" , normal_expr } ;
negident_expr = normal_expr , { "is" , "not" , normal_expr } ;
identity_expr = normal_expr , { "is" , normal_expr } ;
compare_expr = identity_expr | equality_expr | notequal_expr | includes_expr | lesser_expr | greater_expr ;
logical_expr = compare_expr , ( [ "not" ] "in" | "and" | "or" ) , compare_expr ;
expr = normal_expr | assign_expr | compare_expr | logical_expr ;
*)
(* Definitions *)
enum_separator = ">" , identifier ;
enum_value = identifier , [ integer_literal ] , [ text_literal ] ;
enum_defn = "enum" , [ type ] , "{" , { enum_value | enum_separator } , "}" ;
struct_field = identifier , ":" , type , ";" ;
struct_defn = "struct" , "{" , { struct_field } , "}" ;
defn = struct_defn | enum_defn ;
(* Declarations *)
constant_decl = identifier , "::" , ( defn | func_expr | expr , ";" ) ;
mutable_decl = identifier , ":" , ( type | "=" , expr | type , "=" , expr ) ";" ;
decl = constant_decl | mutable_decl ;