module.exports = grammar({ name: 'vm', rules: { source_file: $ => repeat($._item), _item: $ => choice( $.command, $.comment, $._whitespace ), // VM commands command: $ => choice( $.arithmetic_command, $.memory_command, $.program_flow_command, $.function_command ), // Arithmetic and logical commands arithmetic_command: $ => choice( 'add', 'sub', 'neg', 'eq', 'gt', 'lt', 'and', 'or', 'not' ), // Memory access commands memory_command: $ => choice( $.push_command, $.pop_command ), push_command: $ => seq( 'push', $.memory_segment, $.index ), pop_command: $ => seq( 'pop', $.memory_segment, $.index ), // Memory segments memory_segment: $ => choice( 'argument', 'local', 'static', 'constant', 'this', 'that', 'pointer', 'temp' ), // Program flow commands program_flow_command: $ => choice( $.label_command, $.goto_command, $.if_goto_command ), label_command: $ => seq( 'label', $.label_name ), goto_command: $ => seq( 'goto', $.label_name ), if_goto_command: $ => seq( 'if-goto', $.label_name ), // Function calling commands function_command: $ => choice( $.function_declaration, $.call_command, $.return_command ), function_declaration: $ => seq( 'function', $.function_name, $.local_vars_count ), call_command: $ => seq( 'call', $.function_name, $.args_count ), return_command: $ => 'return', // Identifiers and numbers index: $ => /\d+/, local_vars_count: $ => /\d+/, args_count: $ => /\d+/, label_name: $ => /[A-Za-z_][A-Za-z0-9_.$:]*/, function_name: $ => /[A-Za-z_][A-Za-z0-9_.$:]*/, // Comments comment: $ => token(seq('//', /.*/)), // Whitespace _whitespace: $ => /\s+/ }, extras: $ => [ /\s/, $.comment ] });