// References: // [1] Apple II Applesoft BASIC Programmer's Reference Manual, Volume 1, Apple Computer, Inc., Cupertino, 1982 // [2] Apple II Applesoft BASIC Programmer's Reference Manual, Volume 2, Apple Computer, Inc., Cupertino, 1982 // grammar-src.js is for human editing // grammar.js is the actual grammar // After editing this file run `build.py` to regenerate all the products // The term TOKEN may be used in two senses herein: Tokens recognized by the Apple II ROM, // vs. tokens defined by Tree-sitter. The token_processor.py program is // concerned with the former. // This grammar follows Ref. 2 closely. // Ref. 1 is used mainly to construct tests (see ./test/corpus/*) // Limits of a real Apple II that are not imposed here: // * parenthesis to 36 levels // * line numbers cannot exceed 63999 // * subscripts limited to 89 dimensions // * nested loops limited to 10 levels // * length of a line limited to 239 characters // Flags controlling syntax, may be edited by `build.py` const allow_lower_case = true; const allow_call_args = true; const language_name = 'applesoft' /** * combine regex containing simple alternatives * @param {*} lst items can be a character (`/./`) or choice of characters (`/[...]/`) * @returns a RegExp */ function regex_or(lst) { let src = ''; lst.forEach(r => { if (r.source[0] == '[' && r.source[r.source.length - 1] == ']') src += r.source.substring(1, r.source.length - 1); else src += r.source; }); return new RegExp('[' + src + ']'); } // Define constants for use in forming terminal nodes. // These are named after their equivalents in Ref. 2 Appendix B // This real number excludes integers, unlike Ref. 2 p. 237 // Following captures the zero valued cases in the first table on p. 237 // There are no negative numbers outside of unary expressions (DATA might be viewed as an exception) let POS_REAL_DOT = /[0-9]?[0-9 ]*\.[0-9 ]*(E *[+-]? *([0-9] *[0-9]?)?)?/; // Following captures forms without the decimal point let POS_REAL_E = /[0-9][0-9 ]*(E *[+-]? *([0-9] *[0-9]?)?)/; // Real numbers in DATA have greater syntactic range, but lower case is never allowed (E not e). // Also for data allow the sign to be part of the number, since we don't have expressions. const REAL_DATA_DOT = /([+-] *)?[0-9]?[0-9 ]*\.[0-9 ]*(E *[+-]? *([0-9] *[0-9]?)?)?/; const REAL_DATA_E = /([+-] *)?[0-9][0-9 ]*(E *[+-]? *([0-9] *[0-9]?)?)/; const REAL_DATA_BARE = /([+-]|[+-]? *E *[+-]?)/; const INTEGER_DATA = /([+-] *)?[0-9]([0-9 ]*[0-9])?/; if (allow_lower_case) { POS_REAL_DOT = new RegExp(POS_REAL_DOT.source.replace('E','[Ee]')); POS_REAL_E = new RegExp(POS_REAL_E.source.replace('E','[Ee]')); } const DIGIT = /[0-9]/, LETTER = /[A-Za-z]/, POS_INTEGER = /[0-9]([0-9 ]*[0-9])?/, QUOTE = /"/, SPACE = / /, COMMA = /,/, COLON = /:/, // Ref. 2 includes any control character in SPCHAR, while we exclude NULL, LF, CR. SPCHAR_NO_SEP = /[+\-*\/^=<>().;%$#?&'@!\[\]{}\\|_`~\x01-\x09\x0b\x0c\x0e-\x1f]/, SPCHAR = regex_or([SPCHAR_NO_SEP,COMMA,COLON]), SCHAR = regex_or([LETTER,DIGIT,SPCHAR,SPACE]), RUN = new RegExp(SCHAR.source + '\x2a'), // DCHAR_1 and DCHAR_N replace `character` from Ref. 2, used for DATA literal // Ref. 2 erroneously allows commas and colons in DATA literals. // Also, leading spaces are ignored, but trailing spaces are included. // This treatment of spaces is consistent with READ but not the tokenizer. DCHAR_1 = regex_or([LETTER,DIGIT,SPCHAR_NO_SEP]), DCHAR_N = regex_or([DCHAR_1,QUOTE,SPACE]); // Tree-sitter grammar definition module.exports = grammar({ name: language_name, extras: $ => [' '], // "name" is the term given in Ref. 2 for an identifier. // external scanner is used to forbid keywords from appearing anywhere in the name. externals: $ => [ $._ext_name ], rules: { source_file: $ => repeat(choice($.line,$._empty_line)), // Program lines line: $ => seq($.linenum, repeat(':'), repeat(seq($.statement,repeat1(':'))), seq($.statement,repeat(':')), $._newline), linenum: $ => / *[0-9][0-9 ]*/, _newline: $ => /\r?\n/, _empty_line: $ => /\r?\n/, // Would not exist on real Apple II // Assign a rule to all tokenized statements and functions // These are taken from Table H-3 in Ref. 2 tok_end: $ => /[Ee] *[Nn] *[Dd]/, tok_for: $ => /[Ff] *[Oo] *[Rr]/, tok_next: $ => /[Nn] *[Ee] *[Xx] *[Tt]/, tok_data: $ => /[Dd] *[Aa] *[Tt] *[Aa]/, tok_input: $ => /[Ii] *[Nn] *[Pp] *[Uu] *[Tt]/, tok_del: $ => /[Dd] *[Ee] *[Ll]/, tok_dim: $ => /[Dd] *[Ii] *[Mm]/, tok_read: $ => /[Rr] *[Ee] *[Aa] *[Dd]/, tok_gr: $ => /[Gg] *[Rr]/, tok_text: $ => /[Tt] *[Ee] *[Xx] *[Tt]/, tok_prn: $ => /[Pp] *[Rr] *[##]/, tok_inn: $ => /[Ii] *[Nn] *[##]/, tok_call: $ => /[Cc] *[Aa] *[Ll] *[Ll]/, tok_plot: $ => /[Pp] *[Ll] *[Oo] *[Tt]/, tok_hlin: $ => /[Hh] *[Ll] *[Ii] *[Nn]/, tok_vlin: $ => /[Vv] *[Ll] *[Ii] *[Nn]/, tok_hgr2: $ => /[Hh] *[Gg] *[Rr] *[22]/, tok_hgr: $ => /[Hh] *[Gg] *[Rr]/, tok_hcoloreq: $ => /[Hh] *[Cc] *[Oo] *[Ll] *[Oo] *[Rr] *[==]/, tok_hplot: $ => /[Hh] *[Pp] *[Ll] *[Oo] *[Tt]/, tok_draw: $ => /[Dd] *[Rr] *[Aa] *[Ww]/, tok_xdraw: $ => /[Xx] *[Dd] *[Rr] *[Aa] *[Ww]/, tok_htab: $ => /[Hh] *[Tt] *[Aa] *[Bb]/, tok_home: $ => /[Hh] *[Oo] *[Mm] *[Ee]/, tok_roteq: $ => /[Rr] *[Oo] *[Tt] *[==]/, tok_scaleeq: $ => /[Ss] *[Cc] *[Aa] *[Ll] *[Ee] *[==]/, tok_shload: $ => /[Ss] *[Hh] *[Ll] *[Oo] *[Aa] *[Dd]/, tok_trace: $ => /[Tt] *[Rr] *[Aa] *[Cc] *[Ee]/, tok_notrace: $ => /[Nn] *[Oo] *[Tt] *[Rr] *[Aa] *[Cc] *[Ee]/, tok_normal: $ => /[Nn] *[Oo] *[Rr] *[Mm] *[Aa] *[Ll]/, tok_inverse: $ => /[Ii] *[Nn] *[Vv] *[Ee] *[Rr] *[Ss] *[Ee]/, tok_flash: $ => /[Ff] *[Ll] *[Aa] *[Ss] *[Hh]/, tok_coloreq: $ => /[Cc] *[Oo] *[Ll] *[Oo] *[Rr] *[==]/, tok_pop: $ => /[Pp] *[Oo] *[Pp]/, tok_vtab: $ => /[Vv] *[Tt] *[Aa] *[Bb]/, tok_himem: $ => /[Hh] *[Ii] *[Mm] *[Ee] *[Mm] *[::]/, tok_lomem: $ => /[Ll] *[Oo] *[Mm] *[Ee] *[Mm] *[::]/, tok_onerr: $ => /[Oo] *[Nn] *[Ee] *[Rr] *[Rr]/, tok_resume: $ => /[Rr] *[Ee] *[Ss] *[Uu] *[Mm] *[Ee]/, tok_recall: $ => /[Rr] *[Ee] *[Cc] *[Aa] *[Ll] *[Ll]/, tok_store: $ => /[Ss] *[Tt] *[Oo] *[Rr] *[Ee]/, tok_speedeq: $ => /[Ss] *[Pp] *[Ee] *[Ee] *[Dd] *[==]/, tok_let: $ => /[Ll] *[Ee] *[Tt]/, tok_goto: $ => /[Gg] *[Oo] *[Tt] *[Oo]/, tok_run: $ => /[Rr] *[Uu] *[Nn]/, tok_if: $ => /[Ii] *[Ff]/, tok_restore: $ => /[Rr] *[Ee] *[Ss] *[Tt] *[Oo] *[Rr] *[Ee]/, tok_amp: $ => '&', tok_gosub: $ => /[Gg] *[Oo] *[Ss] *[Uu] *[Bb]/, tok_return: $ => /[Rr] *[Ee] *[Tt] *[Uu] *[Rr] *[Nn]/, tok_rem: $ => /[Rr] *[Ee] *[Mm]/, tok_stop: $ => /[Ss] *[Tt] *[Oo] *[Pp]/, tok_on: $ => /[Oo] *[Nn]/, tok_wait: $ => /[Ww] *[Aa] *[Ii] *[Tt]/, tok_load: $ => /[Ll] *[Oo] *[Aa] *[Dd]/, tok_save: $ => /[Ss] *[Aa] *[Vv] *[Ee]/, tok_def: $ => /[Dd] *[Ee] *[Ff]/, tok_poke: $ => /[Pp] *[Oo] *[Kk] *[Ee]/, tok_print: $ => /[Pp] *[Rr] *[Ii] *[Nn] *[Tt]|\?/, tok_cont: $ => /[Cc] *[Oo] *[Nn] *[Tt]/, tok_list: $ => /[Ll] *[Ii] *[Ss] *[Tt]/, tok_clear: $ => /[Cc] *[Ll] *[Ee] *[Aa] *[Rr]/, tok_get: $ => /[Gg] *[Ee] *[Tt]/, tok_new: $ => /[Nn] *[Ee] *[Ww]/, tok_tabp: $ => /[Tt] *[Aa] *[Bb] *[\(\(]/, tok_to: $ => /[Tt] *[Oo]/, tok_fn: $ => /[Ff] *[Nn]/, tok_spcp: $ => /[Ss] *[Pp] *[Cc] *[\(\(]/, tok_then: $ => /[Tt] *[Hh] *[Ee] *[Nn]/, tok_at: $ => /[Aa] *[Tt]/, tok_not: $ => /[Nn] *[Oo] *[Tt]/, tok_step: $ => /[Ss] *[Tt] *[Ee] *[Pp]/, tok_plus: $ => '+', tok_minus: $ => '-', tok_times: $ => '*', tok_div: $ => '/', tok_pow: $ => '^', tok_and: $ => /[Aa] *[Nn] *[Dd]/, tok_or: $ => /[Oo] *[Rr]/, tok_gtr: $ => '>', tok_eq: $ => '=', tok_less: $ => '<', tok_sgn: $ => /[Ss] *[Gg] *[Nn]/, tok_int: $ => /[Ii] *[Nn] *[Tt]/, tok_abs: $ => /[Aa] *[Bb] *[Ss]/, tok_usr: $ => /[Uu] *[Ss] *[Rr]/, tok_fre: $ => /[Ff] *[Rr] *[Ee]/, tok_scrnp: $ => /[Ss] *[Cc] *[Rr] *[Nn] *[\(\(]/, tok_pdl: $ => /[Pp] *[Dd] *[Ll]/, tok_pos: $ => /[Pp] *[Oo] *[Ss]/, tok_sqr: $ => /[Ss] *[Qq] *[Rr]/, tok_rnd: $ => /[Rr] *[Nn] *[Dd]/, tok_log: $ => /[Ll] *[Oo] *[Gg]/, tok_exp: $ => /[Ee] *[Xx] *[Pp]/, tok_cos: $ => /[Cc] *[Oo] *[Ss]/, tok_sin: $ => /[Ss] *[Ii] *[Nn]/, tok_tan: $ => /[Tt] *[Aa] *[Nn]/, tok_atn: $ => /[Aa] *[Tt][Nn]/, tok_peek: $ => /[Pp] *[Ee] *[Ee] *[Kk]/, tok_len: $ => /[Ll] *[Ee] *[Nn]/, tok_str: $ => /[Ss] *[Tt] *[Rr] *[\$\$]/, tok_val: $ => /[Vv] *[Aa] *[Ll]/, tok_asc: $ => /[Aa] *[Ss] *[Cc]/, tok_chr: $ => /[Cc] *[Hh] *[Rr] *[\$\$]/, tok_left: $ => /[Ll] *[Ee] *[Ff] *[Tt] *[\$\$]/, tok_right: $ => /[Rr] *[Ii] *[Gg] *[Hh] *[Tt] *[\$\$]/, tok_mid: $ => /[Mm] *[Ii] *[Dd] *[\$\$]/, // Statements from Appendix A statement: $ => choice( $.assignment, allow_call_args ? seq($.tok_call, $._aexpr, optional($.str), repeat(seq(',', $._expr))) : seq($.tok_call, $._aexpr, optional($.str)), $.tok_clear, seq($.tok_coloreq,$._aexpr), $.tok_cont, seq($.tok_data,optional($._data_item),repeat(seq(',',optional($._data_item)))), seq($.tok_def,$.tok_fn,alias($.name_real,$.name_fn),'(',alias($._real_scalar,$.var_real),')',$.tok_eq,$._aexpr), seq($.tok_del,$.linenum,',',$.linenum), seq($.tok_dim,$.dim_item,repeat(seq(',',$.dim_item))), seq($.tok_draw,$._aexpr,optional(seq($.tok_at,$._aexpr,',',$._aexpr))), $.tok_end, $.tok_flash, seq($.tok_for,alias($._real_scalar,$.var_real),$.tok_eq,$._aexpr,$.tok_to,$._aexpr,optional(seq($.tok_step,$._aexpr))), seq($.tok_get,$._var,repeat(seq(',',$._var))), seq($.tok_gosub,$.linenum), seq($.tok_goto,$.linenum), $.tok_gr, seq($.tok_hcoloreq,$._aexpr), $.tok_hgr, $.tok_hgr2, seq($.tok_himem,$._aexpr), seq($.tok_hlin,$._aexpr,',',$._aexpr,$.tok_at,$._aexpr), $.tok_home, seq($.tok_hplot,optional($.tok_to),$._aexpr,',',$._aexpr,repeat(seq($.tok_to,$._aexpr,',',$._aexpr))), seq($.tok_htab,$._aexpr), // Ref. 2 explicitly has the compound statement, but this is implied seq($.tok_if,$._expr,$.tok_then,$.statement), seq($.tok_if,$._expr,$.tok_then,$.linenum), seq($.tok_if,$._expr,$.tok_goto,$.linenum), seq($.tok_inn,$._aexpr), seq($.tok_input,optional(seq($.str,';')),$._var,repeat(seq(',',$._var))), $.tok_inverse, $.tok_load, // cassette tape seq($.tok_list,optional($.linenum),optional(seq(choice($.tok_minus,','),optional($.linenum)))), seq($.tok_lomem,$._aexpr), $.tok_new, seq($.tok_next,optional(seq($._avar,repeat(seq(',',$._avar))))), $.tok_normal, $.tok_notrace, seq($.tok_on,$._aexpr,choice($.tok_goto,$.tok_gosub),$.linenum,repeat(seq(',',$.linenum))), seq($.tok_onerr,$.tok_goto,$.linenum), seq($.tok_plot,$._aexpr,',',$._aexpr), seq($.tok_poke,$._aexpr,',',$._aexpr), $.tok_pop, seq($.tok_prn,$._aexpr), seq($.tok_print,repeat((choice(',',';',$._expr)))), seq($.tok_read,$._var,repeat(seq(',',$._var))), seq($.tok_recall,choice(alias($._int_scalar,$.var_int),alias($._real_scalar,$.var_real))), // cassette tape, subscript omitted seq($.tok_rem,optional($.comment_text)), $.tok_restore, $.tok_resume, $.tok_return, seq($.tok_roteq,$._aexpr), seq($.tok_run,optional($.linenum)), $.tok_save, // cassette tape seq($.tok_scaleeq,$._aexpr), $.tok_shload, // cassette tape seq($.tok_speedeq,$._aexpr), $.tok_stop, seq($.tok_store,choice(alias($._int_scalar,$.var_int),alias($._real_scalar,$.var_real))), // cassette tape, subscript omitted $.tok_text, $.tok_trace, seq($.tok_vlin,$._aexpr,',',$._aexpr,$.tok_at,$._aexpr), seq($.tok_vtab,$._aexpr), seq($.tok_wait,$._aexpr,',',$._aexpr,optional(seq(',',$._aexpr))), seq($.tok_xdraw,$._aexpr,optional(seq($.tok_at,$._aexpr,',',$._aexpr))), seq($.tok_amp,$.str,optional($._amp_prolog_sep),optional($._amp_arg)), seq($.tok_amp, optional($.name_amp), '(', $._expr_list, ')'), seq($.tok_amp,alias($.retok,$.name_amp),$._amp_arg), seq($.tok_amp, $.name_amp, optional(seq($._amp_prolog_sep, $._amp_arg))) ), comment_text: $ => /.+/, assignment: $ => choice( seq(optional($.tok_let),$._avar,$.tok_eq,$._aexpr), seq(optional($.tok_let),$.var_str,$.tok_eq,$._sexpr) ), // Numerical functions from Appendix A // N.b. some have left parenthesis as part of the token // following is the general fcall from Ref. 2 (not used) //fcall: $=> seq($.name,'(',repeat(seq($._expr,',')),$._expr,')'), fcall: $ => choice( seq($.tok_abs,'(',$._aexpr,')'), seq($.tok_asc,'(',$._sexpr,')'), seq($.tok_atn,'(',$._aexpr,')'), seq($.tok_cos,'(',$._aexpr,')'), seq($.tok_exp,'(',$._aexpr,')'), seq($.tok_fn,alias($.name_real,$.name_fn),'(',$._aexpr,')'), seq($.tok_fre,'(',$._expr,')'), seq($.tok_int,'(',$._aexpr,')'), seq($.tok_len,'(',$._sexpr,')'), seq($.tok_log,'(',$._aexpr,')'), seq($.tok_pdl,'(',$._aexpr,')'), seq($.tok_peek,'(',$._aexpr,')'), seq($.tok_pos,'(',$._expr,')'), seq($.tok_rnd,'(',$._aexpr,')'), seq($.tok_scrnp,$._aexpr,',',$._aexpr,')'), seq($.tok_sgn,'(',$._aexpr,')'), seq($.tok_sin,'(',$._aexpr,')'), seq($.tok_sqr,'(',$._aexpr,')'), seq($.tok_tan,'(',$._aexpr,')'), seq($.tok_usr,'(',$._aexpr,')'), seq($.tok_val,'(',$._sexpr,')') ), // String functions from Appendix A // N.b. some have left parenthesis as part of the token // following is the general sfcall from Ref. 2 (not used) //sfcall: $ => seq($.name_str,'(',repeat(seq($._expr,',')),$._expr,')'), sfcall: $ => choice( seq($.tok_chr,'(',$._aexpr,')'), seq($.tok_left,'(',$._sexpr,',',$._aexpr,')'), seq($.tok_mid,'(',$._sexpr,',',$._aexpr,optional(seq(',',$._aexpr)),')'), seq($.tok_right,'(',$._sexpr,',',$._aexpr,')'), seq($.tok_spcp,$._aexpr,')'), seq($.tok_str,'(',$._aexpr,')'), seq($.tok_tabp,$._aexpr,')') ), // Expressions from Appendix B _expr: $ => choice($._aexpr,$._sexpr), _aexpr: $ => choice( $.real, $.int, $._avar, $.fcall, $.unary_aexpr, $.binary_aexpr, $._parenthesized_aexpr // following are the way unary and binary aexpr defined in Ref. 2 (not used) //seq($.unop,$._aexpr), //seq($._aexpr,$.alop,$._aexpr), //seq($._sexpr,$._relop,$._sexpr), ), unary_aexpr: $ => prec(7,choice( seq($.tok_plus,$._aexpr), seq($.tok_minus,$._aexpr), seq($.tok_not,$._aexpr) )), binary_aexpr: $ => choice( prec.left(6,seq($._aexpr,$.tok_pow,$._aexpr)), prec.left(5,seq($._aexpr,choice($.tok_times,$.tok_div),$._aexpr)), prec.left(4,seq($._aexpr,choice($.tok_plus,$.tok_minus),$._aexpr)), prec.left(3,seq($._aexpr,$._relop,$._aexpr)), prec.left(3,seq($._sexpr,$._relop,$._sexpr)), prec.left(2,seq($._aexpr,$.tok_and,$._aexpr)), prec.left(1,seq($._aexpr,$.tok_or,$._aexpr)) ), _parenthesized_aexpr: $ => prec(1,seq('(',$._aexpr,')')), _relop: $ => choice($.tok_eq,$.tok_less,$.tok_gtr, seq($.tok_less,$.tok_eq),seq($.tok_eq,$.tok_less), seq($.tok_gtr,$.tok_eq),seq($.tok_eq,$.tok_gtr), seq($.tok_less,$.tok_gtr),seq($.tok_gtr,$.tok_less)), // following are some operator groups defined by Ref.2 but not used here //alop: $ => choice($.aop,$._relop,$.lop), //aop: $ => choice($.tok_plus,$.tok_minus,$.tok_times,$.tok_div,$.tok_pow), //lop: $ => choice($.tok_and,$.tok_or), //unop: $ => choice($.tok_plus,$.tok_minus,$.tok_not), _sexpr: $ => choice( $.str, $.var_str, $.sfcall, $.binary_sexpr, $._parenthesized_sexpr ), binary_sexpr: $ => prec.left(1,seq($._sexpr,$._sop,$._sexpr)), _parenthesized_sexpr: $ => seq('(',$._sexpr,')'), _sop: $ => $.tok_plus, // Variables from Appendix B // Renamed: intvar -> var_int, realvar -> var_real, svar -> var_str _var: $ => choice($._avar,$.var_str), _avar: $ => choice($.var_real,$.var_int), var_int: $ => choice($.name_int,$._int_array), var_real: $ => choice($.name_real,$._real_array), var_str: $ => choice($.name_str,$._str_array), subscript: $ => seq('(',$._aexpr,repeat(seq(',',$._aexpr)),')'), dim_item: $ => choice( alias($._int_array, $.var_int), alias($._real_array, $.var_real), alias($._str_array, $.var_str)), // DATA items // DATA is rather tricky because it is parsed in 2 or 3 different ways: // by the tokenizer, by READ, and possibly by the execution parser. // Unfortunately these are not consistent. This parser emulates // READ, and therefore not the tokenizer. Downstream tools need to // be aware of this. The authors of Appendix B did not address this, // and their definition of the `literal` is surely problematic. _data_item: $ => choice(alias($.str,$.data_str),$.data_literal,$.data_int,$.data_real), data_int: $ => INTEGER_DATA, data_real: $ => choice(REAL_DATA_DOT,REAL_DATA_E,REAL_DATA_BARE), data_literal: $ => token(prec(0,seq(DCHAR_1,repeat(DCHAR_N)))), // Items to build ampersand commands _expr_list: $ => seq($._expr, repeat(seq(',', $._expr))), _amp_sep: $ => choice(...'!@#;_{}[]\\|', $.tok_to, $.tok_at, $.tok_step, $.tok_then, $.tok_goto, $.tok_gosub), _amp_prolog_sep: $ => choice($._amp_sep,choice($.tok_pow,$.tok_times,$.tok_minus,$.tok_eq,$.tok_plus,',','.',$.tok_less,$.tok_gtr,$.tok_div)), retok: $ => prec.left(1,$._retok), name_amp: $ => prec.left(2,choice($._retok, $._name)), _amp_arg: $ => seq($._expr_list, repeat(seq($._amp_sep, $._expr_list))), _retok: $ => choice($.tok_end,$.tok_for,$.tok_next,$.tok_data,$.tok_input,$.tok_del,$.tok_dim,$.tok_read,$.tok_gr,$.tok_text,$.tok_prn,$.tok_inn,$.tok_call,$.tok_plot,$.tok_hlin,$.tok_vlin,$.tok_hgr2,$.tok_hgr,$.tok_hcoloreq,$.tok_hplot,$.tok_draw,$.tok_xdraw,$.tok_htab,$.tok_home,$.tok_roteq,$.tok_scaleeq,$.tok_shload,$.tok_trace,$.tok_notrace,$.tok_normal,$.tok_inverse,$.tok_flash,$.tok_coloreq,$.tok_pop,$.tok_vtab,$.tok_himem,$.tok_lomem,$.tok_onerr,$.tok_resume,$.tok_recall,$.tok_store,$.tok_speedeq,$.tok_let,$.tok_goto,$.tok_run,$.tok_if,$.tok_restore,$.tok_gosub,$.tok_return,$.tok_rem,$.tok_stop,$.tok_on,$.tok_wait,$.tok_load,$.tok_save,$.tok_def,$.tok_poke,$.tok_print,$.tok_cont,$.tok_list,$.tok_clear,$.tok_get,$.tok_new,$.tok_tabp,$.tok_to,$.tok_fn,$.tok_spcp,$.tok_then,$.tok_at,$.tok_not,$.tok_step,$.tok_and,$.tok_or,$.tok_sgn,$.tok_int,$.tok_abs,$.tok_usr,$.tok_fre,$.tok_scrnp,$.tok_pdl,$.tok_pos,$.tok_sqr,$.tok_rnd,$.tok_log,$.tok_exp,$.tok_cos,$.tok_sin,$.tok_tan,$.tok_atn,$.tok_peek,$.tok_len,$.tok_str,$.tok_val,$.tok_asc,$.tok_chr,$.tok_left,$.tok_right,$.tok_mid), // Literals from Appendix B int: $ => token(prec(1,POS_INTEGER)), real: $ => token(prec(1,choice(POS_REAL_DOT,POS_REAL_E))), str: $ => prec.right(seq('"',RUN,optional('"'))), // "Extra" items not in Appendix B // These are added for convenience or to account for certain exceptions name_real: $ => $._name, name_int: $ => seq($._name,'%'), name_str: $ => seq($._name,'$'), _real_array: $ => prec(1,seq($.name_real,$.subscript)), _int_array: $ => prec(1,seq($.name_int,$.subscript)), _str_array: $ => prec(1, seq($.name_str,$.subscript)), _real_scalar: $ => $.name_real, _int_scalar: $ => $.name_int, // This is the rule that triggers the external scanner. // Due to tree-sitter design, lexing a variable name requires two stages: // (i) lookahead: find maximum run of a valid variable name, and return empty token // (ii) advance: add the actual characters _name: $ => seq($._ext_name,$._ext_name) } });