const PREC = {
|
|
ASSIGNMENT: -1,
|
|
CONDITIONAL: -2,
|
|
DEFAULT: 0,
|
|
LOGICAL_OR: 1,
|
|
LOGICAL_AND: 2,
|
|
INCLUSIVE_OR: 3,
|
|
EXCLUSIVE_OR: 4,
|
|
BITWISE_AND: 5,
|
|
EQUAL: 6,
|
|
RELATIONAL: 7,
|
|
SIZEOF: 8,
|
|
SHIFT: 9,
|
|
ADD: 10,
|
|
MULTIPLY: 11,
|
|
CAST: 12,
|
|
UNARY: 13,
|
|
CALL: 14,
|
|
FIELD: 15,
|
|
SUBSCRIPT: 16
|
|
};
|
|
|
|
module.exports = grammar({
|
|
name: 'c',
|
|
|
|
extras: $ => [
|
|
/\s/,
|
|
$.comment,
|
|
],
|
|
|
|
inline: $ => [
|
|
$._statement,
|
|
$._top_level_item,
|
|
$._compound_statement_item,
|
|
$._type_identifier,
|
|
$._field_identifier,
|
|
$._statement_identifier,
|
|
],
|
|
|
|
conflicts: $ => [
|
|
[$._type_specifier, $._declarator],
|
|
[$._type_specifier, $._declarator, $.macro_type_specifier],
|
|
[$._type_specifier, $._expression],
|
|
[$._type_specifier, $._expression, $.macro_type_specifier],
|
|
[$._type_specifier, $.macro_type_specifier],
|
|
[$.sized_type_specifier],
|
|
],
|
|
|
|
rules: {
|
|
translation_unit: $ => repeat($._top_level_item),
|
|
|
|
_top_level_item: $ => choice(
|
|
$.function_definition,
|
|
$.linkage_specification,
|
|
$.declaration,
|
|
$.type_definition,
|
|
$._empty_declaration,
|
|
$.preproc_if,
|
|
$.preproc_ifdef,
|
|
$.preproc_include,
|
|
$.preproc_def,
|
|
$.preproc_function_def,
|
|
$.preproc_call
|
|
),
|
|
|
|
_compound_statement_item: $ => choice(
|
|
$._statement,
|
|
$.declaration,
|
|
$.type_definition,
|
|
$._empty_declaration,
|
|
alias($.preproc_if_in_compound_statement, $.preproc_if),
|
|
alias($.preproc_ifdef_in_compound_statement, $.preproc_ifdef),
|
|
$.preproc_include,
|
|
$.preproc_def,
|
|
$.preproc_function_def,
|
|
$.preproc_call
|
|
),
|
|
|
|
// Preprocesser
|
|
|
|
preproc_include: $ => seq(
|
|
preprocessor('include'),
|
|
choice($.string_literal, $.system_lib_string)
|
|
),
|
|
|
|
preproc_def: $ => seq(
|
|
preprocessor('define'),
|
|
$.identifier,
|
|
optional(seq(/[ \t]+/, $.preproc_arg)),
|
|
'\n'
|
|
),
|
|
|
|
preproc_function_def: $ => seq(
|
|
preprocessor('define'),
|
|
$.identifier,
|
|
$.preproc_params,
|
|
optional($.preproc_arg),
|
|
'\n'
|
|
),
|
|
|
|
preproc_params: $ => seq(
|
|
'(', commaSep(choice($.identifier, '...')), ')'
|
|
),
|
|
|
|
preproc_call: $ => seq(
|
|
$.preproc_directive,
|
|
optional(seq(/[ \t]+/, $.preproc_arg)),
|
|
'\n'
|
|
),
|
|
|
|
preproc_if: $ => seq(
|
|
preprocessor('if'),
|
|
$.preproc_arg,
|
|
repeat($._top_level_item),
|
|
optional(choice($.preproc_else, $.preproc_elif)),
|
|
preprocessor('endif')
|
|
),
|
|
|
|
preproc_if_in_compound_statement: $ => seq(
|
|
preprocessor('if'),
|
|
$.preproc_arg,
|
|
repeat($._compound_statement_item),
|
|
optional(choice(
|
|
alias($.preproc_else_in_compound_statement, $.preproc_else),
|
|
alias($.preproc_elif_in_compound_statement, $.preproc_elif)
|
|
)),
|
|
preprocessor('endif')
|
|
),
|
|
|
|
preproc_ifdef: $ => seq(
|
|
choice(preprocessor('ifdef'), preprocessor('ifndef')),
|
|
$.identifier,
|
|
repeat($._top_level_item),
|
|
optional(choice($.preproc_else, $.preproc_elif)),
|
|
preprocessor('endif')
|
|
),
|
|
|
|
preproc_ifdef_in_compound_statement: $ => seq(
|
|
choice(preprocessor('ifdef'), preprocessor('ifndef')),
|
|
$.identifier,
|
|
repeat($._compound_statement_item),
|
|
optional(choice(
|
|
alias($.preproc_else_in_compound_statement, $.preproc_else),
|
|
alias($.preproc_elif_in_compound_statement, $.preproc_elif)
|
|
)),
|
|
preprocessor('endif')
|
|
),
|
|
|
|
preproc_elif: $ => seq(
|
|
preprocessor('elif'),
|
|
$.preproc_arg,
|
|
repeat($._top_level_item),
|
|
optional(choice($.preproc_elif, $.preproc_else))
|
|
),
|
|
|
|
preproc_elif_in_compound_statement: $ => seq(
|
|
preprocessor('elif'),
|
|
$.preproc_arg,
|
|
repeat($._compound_statement_item),
|
|
optional(choice(
|
|
alias($.preproc_elif_in_compound_statement, $.preproc_elif),
|
|
alias($.preproc_else_in_compound_statement, $.preproc_else)
|
|
))
|
|
),
|
|
|
|
preproc_else: $ => seq(
|
|
preprocessor('else'),
|
|
repeat($._top_level_item)
|
|
),
|
|
|
|
preproc_else_in_compound_statement: $ => seq(
|
|
preprocessor('else'),
|
|
repeat($._compound_statement_item)
|
|
),
|
|
|
|
preproc_directive: $ => /#[ \t]*[a-zA-Z]\w*/,
|
|
preproc_arg: $ => token(prec(-1, repeat1(choice(/./, '\\\n')))),
|
|
|
|
// Main Grammar
|
|
|
|
function_definition: $ => seq(
|
|
$._declaration_specifiers,
|
|
$._declarator,
|
|
$.compound_statement
|
|
),
|
|
|
|
declaration: $ => seq(
|
|
$._declaration_specifiers,
|
|
commaSep1(choice(
|
|
$._declarator,
|
|
$.init_declarator
|
|
)),
|
|
';'
|
|
),
|
|
|
|
type_definition: $ => seq(
|
|
'typedef',
|
|
repeat($.type_qualifier),
|
|
$._type_specifier,
|
|
$._type_declarator,
|
|
';'
|
|
),
|
|
|
|
_declaration_specifiers: $ => seq(
|
|
repeat(choice(
|
|
$.storage_class_specifier,
|
|
$.type_qualifier
|
|
)),
|
|
$._type_specifier,
|
|
repeat(choice(
|
|
$.storage_class_specifier,
|
|
$.type_qualifier
|
|
))
|
|
),
|
|
|
|
linkage_specification: $ => seq(
|
|
'extern',
|
|
$.string_literal,
|
|
choice(
|
|
$.function_definition,
|
|
$.declaration,
|
|
$.declaration_list
|
|
)
|
|
),
|
|
|
|
declaration_list: $ => seq(
|
|
'{',
|
|
repeat($._top_level_item),
|
|
'}'
|
|
),
|
|
|
|
_declarator: $ => choice(
|
|
$.pointer_declarator,
|
|
$.function_declarator,
|
|
$.array_declarator,
|
|
seq('(', $._declarator, ')'),
|
|
$.identifier
|
|
),
|
|
|
|
_field_declarator: $ => choice(
|
|
alias($.pointer_field_declarator, $.pointer_declarator),
|
|
alias($.function_field_declarator, $.function_declarator),
|
|
alias($.array_field_declarator, $.array_declarator),
|
|
seq('(', $._field_declarator, ')'),
|
|
$._field_identifier
|
|
),
|
|
|
|
_type_declarator: $ => choice(
|
|
alias($.pointer_type_declarator, $.pointer_declarator),
|
|
alias($.function_type_declarator, $.function_declarator),
|
|
alias($.array_type_declarator, $.array_declarator),
|
|
seq('(', $._type_declarator, ')'),
|
|
$._type_identifier
|
|
),
|
|
|
|
_abstract_declarator: $ => choice(
|
|
$.abstract_pointer_declarator,
|
|
$.abstract_function_declarator,
|
|
$.abstract_array_declarator,
|
|
prec(1, seq('(', $._abstract_declarator, ')'))
|
|
),
|
|
|
|
pointer_declarator: $ => prec.right(seq('*', $._declarator)),
|
|
pointer_field_declarator: $ => prec.right(seq('*', $._field_declarator)),
|
|
pointer_type_declarator: $ => prec.right(seq('*', $._type_declarator)),
|
|
abstract_pointer_declarator: $ => prec.right(seq('*', optional($._abstract_declarator))),
|
|
|
|
function_declarator: $ => prec(1, seq($._declarator, $.parameter_list)),
|
|
function_field_declarator: $ => prec(1, seq($._field_declarator, $.parameter_list)),
|
|
function_type_declarator: $ => prec(1, seq($._type_declarator, $.parameter_list)),
|
|
abstract_function_declarator: $ => prec(1, seq(optional($._abstract_declarator), $.parameter_list)),
|
|
|
|
array_declarator: $ => prec(1, seq(
|
|
$._declarator,
|
|
'[',
|
|
optional($._declaration_specifiers),
|
|
optional($._expression),
|
|
']'
|
|
)),
|
|
array_field_declarator: $ => prec(1, seq(
|
|
$._field_declarator,
|
|
'[',
|
|
optional($._declaration_specifiers),
|
|
optional($._expression),
|
|
']'
|
|
)),
|
|
array_type_declarator: $ => prec(1, seq(
|
|
$._type_declarator,
|
|
'[',
|
|
optional($._declaration_specifiers),
|
|
optional($._expression),
|
|
']'
|
|
)),
|
|
abstract_array_declarator: $ => prec(1, seq(
|
|
optional($._abstract_declarator),
|
|
'[',
|
|
optional($._declaration_specifiers),
|
|
optional($._expression),
|
|
']'
|
|
)),
|
|
|
|
init_declarator: $ => seq(
|
|
$._declarator,
|
|
'=',
|
|
choice($.initializer_list, $._expression)
|
|
),
|
|
|
|
compound_statement: $ => seq(
|
|
'{',
|
|
repeat($._compound_statement_item),
|
|
'}'
|
|
),
|
|
|
|
storage_class_specifier: $ => choice(
|
|
'extern',
|
|
'static' ,
|
|
'auto',
|
|
'register',
|
|
'inline'
|
|
),
|
|
|
|
type_qualifier: $ => choice(
|
|
'const',
|
|
'restrict',
|
|
'volatile',
|
|
'restrict',
|
|
'_Atomic'
|
|
),
|
|
|
|
_type_specifier: $ => choice(
|
|
$.struct_specifier,
|
|
$.union_specifier,
|
|
$.enum_specifier,
|
|
$.macro_type_specifier,
|
|
$.sized_type_specifier,
|
|
$.primitive_type,
|
|
$._type_identifier
|
|
),
|
|
|
|
sized_type_specifier: $ => seq(
|
|
repeat1(choice(
|
|
'unsigned',
|
|
'long',
|
|
'short'
|
|
)),
|
|
optional(choice(
|
|
prec.dynamic(-1, $._type_identifier),
|
|
$.primitive_type
|
|
))
|
|
),
|
|
|
|
primitive_type: $ => token(choice(
|
|
'bool',
|
|
'char',
|
|
'int',
|
|
'float',
|
|
'double',
|
|
'void',
|
|
'size_t',
|
|
'ssize_t',
|
|
'intptr_t',
|
|
'uintptr_t',
|
|
'charptr_t',
|
|
...[8, 16, 32, 64].map(n => `int${n}_t`),
|
|
...[8, 16, 32, 64].map(n => `uint${n}_t`),
|
|
...[8, 16, 32, 64].map(n => `char${n}_t`)
|
|
)),
|
|
|
|
enum_specifier: $ => seq(
|
|
'enum',
|
|
choice(
|
|
seq(
|
|
$._type_identifier,
|
|
optional($.enumerator_list)
|
|
),
|
|
$.enumerator_list
|
|
)
|
|
),
|
|
|
|
enumerator_list: $ => seq(
|
|
'{',
|
|
commaSep($.enumerator),
|
|
optional(','),
|
|
'}'
|
|
),
|
|
|
|
struct_specifier: $ => seq(
|
|
'struct',
|
|
choice(
|
|
seq(
|
|
$._type_identifier,
|
|
optional($.field_declaration_list)
|
|
),
|
|
$.field_declaration_list
|
|
)
|
|
),
|
|
|
|
union_specifier: $ => seq(
|
|
'union',
|
|
choice(
|
|
seq(
|
|
$._type_identifier,
|
|
optional($.field_declaration_list)
|
|
),
|
|
$.field_declaration_list
|
|
)
|
|
),
|
|
|
|
field_declaration_list: $ => seq(
|
|
'{',
|
|
repeat($.field_declaration),
|
|
'}'
|
|
),
|
|
|
|
field_declaration: $ => seq(
|
|
$._declaration_specifiers,
|
|
commaSep($._field_declarator),
|
|
optional(seq(':', $._expression)),
|
|
';'
|
|
),
|
|
|
|
enumerator: $ => seq(
|
|
$.identifier,
|
|
optional(seq('=', $._expression))
|
|
),
|
|
|
|
parameter_list: $ => prec.dynamic(1, seq(
|
|
'(',
|
|
commaSep(choice($.parameter_declaration, '...')),
|
|
')'
|
|
)),
|
|
|
|
parameter_declaration: $ => seq(
|
|
$._declaration_specifiers,
|
|
optional(choice($._declarator, $._abstract_declarator))
|
|
),
|
|
|
|
// Statements
|
|
|
|
_statement: $ => choice(
|
|
$.labeled_statement,
|
|
$.compound_statement,
|
|
$.expression_statement,
|
|
$.if_statement,
|
|
$.switch_statement,
|
|
$.case_statement,
|
|
$.do_statement,
|
|
$.while_statement,
|
|
$.for_statement,
|
|
$.return_statement,
|
|
$.break_statement,
|
|
$.continue_statement,
|
|
$.goto_statement
|
|
),
|
|
|
|
labeled_statement: $ => seq(
|
|
$._statement_identifier,
|
|
':',
|
|
$._statement
|
|
),
|
|
|
|
expression_statement: $ => seq(
|
|
optional(choice(
|
|
$._expression,
|
|
$.comma_expression
|
|
)),
|
|
';'
|
|
),
|
|
|
|
if_statement: $ => prec.right(seq(
|
|
'if',
|
|
'(', $._expression, ')',
|
|
$._statement,
|
|
optional(seq(
|
|
'else',
|
|
$._statement
|
|
))
|
|
)),
|
|
|
|
switch_statement: $ => seq(
|
|
'switch',
|
|
'(', $._expression, ')',
|
|
$._statement
|
|
),
|
|
|
|
case_statement: $ => seq(
|
|
choice(
|
|
seq('case', $._expression),
|
|
'default'
|
|
),
|
|
':',
|
|
choice(
|
|
$._statement,
|
|
$.declaration,
|
|
$.type_definition
|
|
)
|
|
),
|
|
|
|
while_statement: $ => seq(
|
|
'while',
|
|
'(', $._expression, ')',
|
|
$._statement
|
|
),
|
|
|
|
do_statement: $ => seq(
|
|
'do',
|
|
$._statement,
|
|
'while',
|
|
'(', $._expression, ')'
|
|
),
|
|
|
|
for_statement: $ => seq(
|
|
'for',
|
|
'(',
|
|
choice(
|
|
$.declaration,
|
|
seq(optional($._expression), ';')
|
|
),
|
|
optional($._expression), ';',
|
|
commaSep($._expression),
|
|
')',
|
|
$._statement
|
|
),
|
|
|
|
return_statement: $ => seq(
|
|
'return',
|
|
optional($._expression),
|
|
';'
|
|
),
|
|
|
|
break_statement: $ => seq(
|
|
'break', ';'
|
|
),
|
|
|
|
continue_statement: $ => seq(
|
|
'continue', ';'
|
|
),
|
|
|
|
goto_statement: $ => seq(
|
|
'goto',
|
|
$._statement_identifier,
|
|
';'
|
|
),
|
|
|
|
// Expressions
|
|
|
|
_expression: $ => choice(
|
|
$.conditional_expression,
|
|
$.assignment_expression,
|
|
$.logical_expression,
|
|
$.bitwise_expression,
|
|
$.equality_expression,
|
|
$.relational_expression,
|
|
$.shift_expression,
|
|
$.math_expression,
|
|
$.cast_expression,
|
|
$.pointer_expression,
|
|
$.sizeof_expression,
|
|
$.subscript_expression,
|
|
$.call_expression,
|
|
$.field_expression,
|
|
$.compound_literal_expression,
|
|
$.identifier,
|
|
$.number_literal,
|
|
$.string_literal,
|
|
$.true,
|
|
$.false,
|
|
$.null,
|
|
$.concatenated_string,
|
|
$.char_literal,
|
|
$.parenthesized_expression
|
|
),
|
|
|
|
comma_expression: $ => seq(
|
|
$._expression,
|
|
',',
|
|
choice($._expression, $.comma_expression)
|
|
),
|
|
|
|
conditional_expression: $ => prec.right(PREC.CONDITIONAL, seq(
|
|
$._expression,
|
|
'?',
|
|
$._expression,
|
|
':',
|
|
$._expression
|
|
)),
|
|
|
|
assignment_expression: $ => prec.right(PREC.ASSIGNMENT, seq(
|
|
$._expression,
|
|
choice(
|
|
'=',
|
|
'*=',
|
|
'/=',
|
|
'%=',
|
|
'+=',
|
|
'-=',
|
|
'<<=',
|
|
'>>=',
|
|
'&=',
|
|
'^=',
|
|
'|='
|
|
),
|
|
$._expression
|
|
)),
|
|
|
|
pointer_expression: $ => choice(
|
|
prec.left(PREC.UNARY, seq('*', $._expression)),
|
|
prec.left(PREC.UNARY, seq('&', $._expression))
|
|
),
|
|
|
|
logical_expression: $ => choice(
|
|
prec.left(PREC.LOGICAL_OR, seq($._expression, '||', $._expression)),
|
|
prec.left(PREC.LOGICAL_AND, seq($._expression, '&&', $._expression)),
|
|
prec.left(PREC.UNARY, seq('!', $._expression))
|
|
),
|
|
|
|
bitwise_expression: $ => choice(
|
|
prec.left(PREC.INCLUSIVE_OR, seq($._expression, '|', $._expression)),
|
|
prec.left(PREC.EXCLUSIVE_OR, seq($._expression, '^', $._expression)),
|
|
prec.left(PREC.BITWISE_AND, seq($._expression, '&', $._expression)),
|
|
prec.left(PREC.UNARY, seq('~', $._expression))
|
|
),
|
|
|
|
equality_expression: $ => prec.left(PREC.EQUAL, seq(
|
|
$._expression, choice('==', '!='), $._expression
|
|
)),
|
|
|
|
relational_expression: $ => prec.left(PREC.RELATIONAL, seq(
|
|
$._expression, choice('<', '>', '<=', '>='), $._expression
|
|
)),
|
|
|
|
shift_expression: $ => prec.left(PREC.SHIFT, seq(
|
|
$._expression, choice('<<', '>>'), $._expression)
|
|
),
|
|
|
|
math_expression: $ => choice(
|
|
prec.left(PREC.ADD, seq($._expression, '+', $._expression)),
|
|
prec.left(PREC.ADD, seq($._expression, '-', $._expression)),
|
|
prec.left(PREC.MULTIPLY, seq($._expression, '*', $._expression)),
|
|
prec.left(PREC.MULTIPLY, seq($._expression, '/', $._expression)),
|
|
prec.left(PREC.MULTIPLY, seq($._expression, '%', $._expression)),
|
|
prec.right(PREC.UNARY, seq('-', $._expression)),
|
|
prec.right(PREC.UNARY, seq('+', $._expression)),
|
|
prec.right(PREC.UNARY, seq(choice('--', '++'), $._expression)),
|
|
prec.right(PREC.UNARY, seq($._expression, choice('++', '--')))
|
|
),
|
|
|
|
cast_expression: $ => prec(PREC.CAST, seq(
|
|
'(',
|
|
$.type_descriptor,
|
|
')',
|
|
$._expression
|
|
)),
|
|
|
|
type_descriptor: $ => seq(
|
|
repeat($.type_qualifier),
|
|
$._type_specifier,
|
|
optional($._abstract_declarator)
|
|
),
|
|
|
|
sizeof_expression: $ => prec(PREC.SIZEOF, seq(
|
|
'sizeof',
|
|
choice(
|
|
$._expression,
|
|
seq('(', $.type_descriptor, ')')
|
|
)
|
|
)),
|
|
|
|
subscript_expression: $ => prec(PREC.SUBSCRIPT, seq(
|
|
$._expression, '[', $._expression, ']')
|
|
),
|
|
|
|
call_expression: $ => prec(PREC.CALL, seq($._expression, $.argument_list)),
|
|
|
|
argument_list: $ => prec.dynamic(1, seq('(', commaSep($._expression), ')')),
|
|
|
|
field_expression: $ => seq(
|
|
prec(PREC.FIELD, seq(
|
|
$._expression,
|
|
choice('.', '->')
|
|
)),
|
|
$._field_identifier
|
|
),
|
|
|
|
compound_literal_expression: $ => seq(
|
|
'(',
|
|
$.type_descriptor,
|
|
')',
|
|
$.initializer_list
|
|
),
|
|
|
|
parenthesized_expression: $ => seq(
|
|
'(',
|
|
choice($._expression, $.comma_expression),
|
|
')'
|
|
),
|
|
|
|
initializer_list: $ => seq(
|
|
'{',
|
|
commaSep(choice(
|
|
$.initializer_pair,
|
|
$._expression,
|
|
$.initializer_list
|
|
)),
|
|
optional(','),
|
|
'}'
|
|
),
|
|
|
|
initializer_pair: $ => seq(
|
|
repeat1(choice($.subscript_designator, $.field_designator)),
|
|
'=',
|
|
choice($._expression, $.initializer_list)
|
|
),
|
|
|
|
subscript_designator: $ => seq('[', $._expression, ']'),
|
|
|
|
field_designator: $ => seq('.', $._field_identifier),
|
|
|
|
number_literal: $ => token(seq(
|
|
choice(
|
|
/\d+(\.\d+)?/,
|
|
/\d+u/,
|
|
seq('0x', /[0-9a-fA-f]+/),
|
|
seq('0b', /[01]+/)
|
|
),
|
|
repeat(choice('u', 'l', 'U', 'L'))
|
|
)),
|
|
|
|
char_literal: $ => token(seq(
|
|
'\'',
|
|
choice(
|
|
seq(optional('\\'), /[^']/),
|
|
seq('\\', '\'')
|
|
),
|
|
'\''
|
|
)),
|
|
|
|
concatenated_string: $ => seq(
|
|
$.string_literal,
|
|
repeat1($.string_literal)
|
|
),
|
|
|
|
string_literal: $ => token(seq(
|
|
'"',
|
|
repeat(choice(/[^\\"\n]/, /\\./)),
|
|
'"')
|
|
),
|
|
|
|
system_lib_string: $ => token(seq(
|
|
'<',
|
|
repeat(choice(/[^>\n]/, '\\>')),
|
|
'>'
|
|
)),
|
|
|
|
true: $ => token(choice('TRUE', 'true')),
|
|
false: $ => token(choice('FALSE', 'false')),
|
|
null: $ => 'NULL',
|
|
|
|
identifier: $ => /[a-zA-Z_]\w*/,
|
|
|
|
_type_identifier: $ => alias($.identifier, $.type_identifier),
|
|
_field_identifier: $ => alias($.identifier, $.field_identifier),
|
|
_statement_identifier: $ => alias($.identifier, $.statement_identifier),
|
|
|
|
_empty_declaration: $ => seq(
|
|
$._declaration_specifiers,
|
|
';'
|
|
),
|
|
|
|
macro_type_specifier: $ => seq(
|
|
$.identifier,
|
|
'(',
|
|
$.type_descriptor,
|
|
')'
|
|
),
|
|
|
|
// http://stackoverflow.com/questions/13014947/regex-to-match-a-c-style-multiline-comment/36328890#36328890
|
|
comment: $ => token(choice(
|
|
seq('//', /.*/),
|
|
seq(
|
|
'/*',
|
|
/[^*]*\*+([^/*][^*]*\*+)*/,
|
|
'/'
|
|
)
|
|
)),
|
|
}
|
|
});
|
|
|
|
module.exports.PREC = PREC
|
|
|
|
function preprocessor (command) {
|
|
return alias(new RegExp('#[ \t]*' + command), '#' + command)
|
|
}
|
|
|
|
function commaSep (rule) {
|
|
return optional(commaSep1(rule))
|
|
}
|
|
|
|
function commaSep1 (rule) {
|
|
return seq(rule, repeat(seq(',', rule)))
|
|
}
|
|
|
|
function commaSepTrailing (recurSymbol, rule) {
|
|
return choice(rule, seq(recurSymbol, ',', rule))
|
|
}
|