{ grammar, rules } = require("tree-sitter-compiler")
|
|
{ choice, err, repeat, seq, keyword, optional, token, prec } = rules
|
|
|
|
commaSep = (rule) ->
|
|
optional(commaSep1(rule))
|
|
|
|
commaSep1 = (rule) ->
|
|
seq(rule, repeat(seq(",", rule)))
|
|
|
|
module.exports = grammar
|
|
name: 'c',
|
|
|
|
ubiquitous: -> [@comment, /\s/]
|
|
|
|
rules:
|
|
program: -> repeat(choice(
|
|
@preproc_include,
|
|
@preproc_define,
|
|
@preproc_call,
|
|
|
|
# declarations
|
|
@struct_declaration,
|
|
@union_declaration,
|
|
@enum_declaration,
|
|
@function_declaration,
|
|
@var_declaration,
|
|
|
|
@typedef,
|
|
))
|
|
|
|
preproc_include: -> seq(
|
|
keyword("#include"),
|
|
choice(@string, @system_lib_string))
|
|
|
|
preproc_define: -> seq(
|
|
keyword("#define"),
|
|
@identifier,
|
|
/.+/)
|
|
|
|
preproc_call: -> choice(
|
|
seq(@preproc_directive, /.*/))
|
|
|
|
preproc_directive: -> /#\a\w+/
|
|
|
|
typedef: -> seq(
|
|
keyword("typedef"),
|
|
@type,
|
|
@identifier,
|
|
";")
|
|
|
|
var_declaration: -> seq(
|
|
repeat(choice(
|
|
keyword("static"),
|
|
keyword("extern"))),
|
|
@type,
|
|
commaSep1(choice(
|
|
@type_expression,
|
|
@var_assignment)),
|
|
";")
|
|
|
|
function_declaration: -> seq(
|
|
@type,
|
|
@identifier,
|
|
"(", @formal_parameters, ")",
|
|
choice(";", @statement_block))
|
|
|
|
statement_block: -> seq(
|
|
"{", err(repeat(@statement)), "}")
|
|
|
|
statement: -> choice(
|
|
@var_declaration,
|
|
@return_statement,
|
|
@if_statement,
|
|
@expression_statement,
|
|
@statement_block),
|
|
|
|
return_statement: -> seq(
|
|
keyword("return"), @expression, ";")
|
|
|
|
expression_statement: -> seq(
|
|
@expression, ";")
|
|
|
|
if_statement: -> seq(
|
|
keyword("if"), "(", err(@expression), ")",
|
|
@statement,
|
|
optional(seq(
|
|
keyword("else"),
|
|
@statement)))
|
|
|
|
type: -> seq(
|
|
optional(keyword("const")),
|
|
choice(
|
|
@primitive_type,
|
|
@struct_type,
|
|
@enum_type,
|
|
@union_type))
|
|
|
|
primitive_type: -> seq(
|
|
repeat(choice(
|
|
keyword("unsigned"),
|
|
keyword("short"),
|
|
keyword("long"))),
|
|
@identifier)
|
|
|
|
formal_parameters: ->
|
|
err(commaSep(@field))
|
|
|
|
type_expression: -> choice(
|
|
@identifier,
|
|
@pointer_type)
|
|
|
|
pointer_type: -> seq(
|
|
"*", @type_expression)
|
|
|
|
struct_declaration: -> seq(
|
|
@struct_type, ";")
|
|
|
|
struct_type: -> seq(
|
|
keyword("struct"),
|
|
choice(
|
|
@identifier,
|
|
seq(
|
|
optional(@identifier),
|
|
"{", err(repeat(seq(@field, ";"))), "}")))
|
|
|
|
union_declaration: -> seq(
|
|
@union_type, ";")
|
|
|
|
union_type: -> seq(
|
|
keyword("union"),
|
|
choice(
|
|
@identifier,
|
|
seq(
|
|
optional(@identifier),
|
|
"{", err(repeat(seq(@field, ";"))), "}")))
|
|
|
|
enum_declaration: -> seq(
|
|
@enum_type, ";")
|
|
|
|
enum_type: -> seq(
|
|
keyword("enum"),
|
|
choice(
|
|
@identifier,
|
|
seq(
|
|
optional(@identifier),
|
|
"{", err(commaSep(@enum_value)), "}")))
|
|
|
|
enum_value: -> seq(
|
|
@identifier, optional(seq("=", @expression)))
|
|
|
|
field: -> seq(@type, @type_expression)
|
|
|
|
var_assignment: -> seq(@type_expression, "=", @expression)
|
|
|
|
type_modifier: -> choice(
|
|
keyword("const"))
|
|
|
|
expression: -> choice(
|
|
@identifier,
|
|
@bool_op,
|
|
@math_op,
|
|
@assignment,
|
|
@function_call,
|
|
@field_access,
|
|
@deref_field_access,
|
|
@number,
|
|
@string)
|
|
|
|
field_access: -> seq(
|
|
@expression, ".", @identifier)
|
|
|
|
deref_field_access: -> seq(
|
|
@expression, "->", @identifier)
|
|
|
|
function_call: -> seq(
|
|
@expression, "(", err(commaSep(@expression)), ")")
|
|
|
|
math_op: -> choice(
|
|
prec(3, seq("-", @expression)),
|
|
prec(2, seq(@expression, "*", @expression)),
|
|
prec(2, seq(@expression, "/", @expression)),
|
|
prec(1, seq(@expression, "+", @expression)),
|
|
prec(1, seq(@expression, "-", @expression)))
|
|
|
|
bool_op: -> choice(
|
|
prec(3, seq("!", @expression)),
|
|
prec(2, seq(@expression, "&&", @expression)),
|
|
prec(1, seq(@expression, "||", @expression)))
|
|
|
|
assignment: -> seq(
|
|
choice(
|
|
@identifier,
|
|
@field_access,
|
|
@deref_field_access),
|
|
"=",
|
|
@expression)
|
|
|
|
number: -> /\d+(\.\d+)?/
|
|
|
|
string: -> token(seq(
|
|
'"', repeat(choice(/[^"]/, '\\"')), '"'))
|
|
|
|
system_lib_string: -> token(seq(
|
|
'<', repeat(choice(/[^>]/, '\\>')), '>'))
|
|
|
|
identifier: -> /\a\w*/
|
|
|
|
comment: -> token(choice(
|
|
seq("//", /.*/),
|
|
seq("/*", repeat(choice(/[^\*]/, /\*[^/]/)), "*/")))
|