basic101 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -0
- data/Changelog.md +9 -1
- data/Gemfile +9 -8
- data/Gemfile.lock +66 -53
- data/README.md +8 -6
- data/VERSION +1 -1
- data/basic101.gemspec +688 -0
- data/lib/basic101/parser.rb +28 -457
- data/lib/basic101/parser/data_statement.rb +20 -0
- data/lib/basic101/parser/define_function_statement.rb +18 -0
- data/lib/basic101/parser/dim_statement.rb +16 -0
- data/lib/basic101/parser/end_statement.rb +11 -0
- data/lib/basic101/parser/expression.rb +100 -0
- data/lib/basic101/parser/for_statement.rb +17 -0
- data/lib/basic101/parser/function_call.rb +13 -0
- data/lib/basic101/parser/gosub_statement.rb +12 -0
- data/lib/basic101/parser/goto_statement.rb +11 -0
- data/lib/basic101/parser/identifier.rb +87 -0
- data/lib/basic101/parser/if_statement.rb +20 -0
- data/lib/basic101/parser/input_statement.rb +19 -0
- data/lib/basic101/parser/let_statement.rb +13 -0
- data/lib/basic101/parser/next_statement.rb +16 -0
- data/lib/basic101/parser/numeric.rb +34 -0
- data/lib/basic101/parser/on_goto_statement.rb +20 -0
- data/lib/basic101/parser/print_statement.rb +19 -0
- data/lib/basic101/parser/program.rb +17 -0
- data/lib/basic101/parser/randomize_statement.rb +11 -0
- data/lib/basic101/parser/read_statement.rb +12 -0
- data/lib/basic101/parser/reference.rb +36 -0
- data/lib/basic101/parser/remark_statement.rb +11 -0
- data/lib/basic101/parser/restore_statement.rb +12 -0
- data/lib/basic101/parser/return_statement.rb +11 -0
- data/lib/basic101/parser/space.rb +23 -0
- data/lib/basic101/parser/statements.rb +36 -0
- data/lib/basic101/parser/stop_statement.rb +11 -0
- data/lib/basic101/parser/string.rb +17 -0
- data/test/spec/basic_float_spec.rb +2 -2
- data/test/spec/basic_object_spec.rb +1 -1
- data/test/spec/basic_string_spec.rb +2 -2
- data/test/spec/input_reader_spec.rb +11 -11
- data/test/spec/input_spec.rb +5 -5
- data/test/spec/output_spec.rb +3 -3
- data/test/spec/spec_helper.rb +2 -1
- data/test/spec/support/basic_numeric_helpers.rb +3 -3
- metadata +82 -34
@@ -0,0 +1,20 @@
|
|
1
|
+
module Basic101
|
2
|
+
|
3
|
+
class Parser < Parslet::Parser
|
4
|
+
|
5
|
+
rule(:data_statement) do
|
6
|
+
str('DATA') >>
|
7
|
+
(space? >> data_item >>
|
8
|
+
(space? >> str(',') >>
|
9
|
+
space? >> data_item
|
10
|
+
).repeat(0)
|
11
|
+
).as(:data_items)
|
12
|
+
end
|
13
|
+
|
14
|
+
rule(:data_item) do
|
15
|
+
float | integer | quoted_string | unquoted_string
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Basic101
|
2
|
+
|
3
|
+
class Parser < Parslet::Parser
|
4
|
+
|
5
|
+
rule(:define_function_statement) do
|
6
|
+
str('DEF').as(:def) >>
|
7
|
+
space? >> user_defined_function_identifier.as(:identifier) >>
|
8
|
+
(space? >> str('(') >>
|
9
|
+
space? >> scalar_reference_list >>
|
10
|
+
space? >> str(')')
|
11
|
+
).as(:parameters) >>
|
12
|
+
space? >> str('=') >>
|
13
|
+
space? >> expression.as(:expression)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Basic101
|
2
|
+
|
3
|
+
class Parser < Parslet::Parser
|
4
|
+
|
5
|
+
rule(:dim_statement) do
|
6
|
+
str('DIM').as(:dim) >>
|
7
|
+
(space? >> array_reference >>
|
8
|
+
(space? >> str(',') >>
|
9
|
+
space? >> array_reference
|
10
|
+
).repeat(0)
|
11
|
+
).as(:references)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Basic101
|
2
|
+
|
3
|
+
class Parser < Parslet::Parser
|
4
|
+
|
5
|
+
rule(:multiply_op) do
|
6
|
+
(str('*').as(:multiply) |
|
7
|
+
str('/').as(:divide))
|
8
|
+
end
|
9
|
+
|
10
|
+
rule(:addition_op) do
|
11
|
+
(str('+').as(:add) |
|
12
|
+
str('-').as(:subtract))
|
13
|
+
end
|
14
|
+
|
15
|
+
rule(:comparison_op) do
|
16
|
+
(str('=').as(:eq) |
|
17
|
+
str('<>').as(:ne) |
|
18
|
+
str('>=').as(:ge) |
|
19
|
+
str('<=').as(:le)) |
|
20
|
+
str('<').as(:lt) |
|
21
|
+
str('>').as(:gt)
|
22
|
+
end
|
23
|
+
|
24
|
+
rule(:and_op) do
|
25
|
+
str('AND').as(:and)
|
26
|
+
end
|
27
|
+
|
28
|
+
rule(:or_op) do
|
29
|
+
str('OR').as(:or)
|
30
|
+
end
|
31
|
+
|
32
|
+
rule(:factor) do
|
33
|
+
quoted_string |
|
34
|
+
float |
|
35
|
+
integer |
|
36
|
+
function_call |
|
37
|
+
reference |
|
38
|
+
str('(') >> space? >> expression >> space? >> str(')')
|
39
|
+
end
|
40
|
+
|
41
|
+
rule(:power) do
|
42
|
+
(factor.as(:left) >>
|
43
|
+
space? >> str('^').as(:power) >>
|
44
|
+
space? >> power.as(:right)) |
|
45
|
+
factor
|
46
|
+
end
|
47
|
+
|
48
|
+
rule(:negation) do
|
49
|
+
(str('-') >>
|
50
|
+
space? >> power).as(:negation) |
|
51
|
+
power
|
52
|
+
end
|
53
|
+
|
54
|
+
rule(:term) do
|
55
|
+
negation.as(:left) >>
|
56
|
+
(space? >> multiply_op.as(:operator) >>
|
57
|
+
space? >> negation.as(:right)
|
58
|
+
).repeat(1).as(:operations).maybe
|
59
|
+
end
|
60
|
+
|
61
|
+
rule(:simple_expression) do
|
62
|
+
term.as(:left) >>
|
63
|
+
(space? >> addition_op.as(:operator) >>
|
64
|
+
space? >> term.as(:right)
|
65
|
+
).repeat(1).as(:operations).maybe
|
66
|
+
end
|
67
|
+
|
68
|
+
rule(:comparison_expression) do
|
69
|
+
simple_expression.as(:left) >>
|
70
|
+
(space? >> comparison_op.as(:operator) >>
|
71
|
+
space? >> simple_expression.as(:right)
|
72
|
+
).repeat(1).as(:operations).maybe
|
73
|
+
end
|
74
|
+
|
75
|
+
rule(:not_expression) do
|
76
|
+
(str('NOT') >> space? >> comparison_expression).as(:not) |
|
77
|
+
comparison_expression
|
78
|
+
end
|
79
|
+
|
80
|
+
rule(:and_expression) do
|
81
|
+
not_expression.as(:left) >>
|
82
|
+
(space? >> and_op.as(:operator) >>
|
83
|
+
space? >> not_expression.as(:right)
|
84
|
+
).repeat(1).as(:operations).maybe
|
85
|
+
end
|
86
|
+
|
87
|
+
rule(:or_expression) do
|
88
|
+
and_expression.as(:left) >>
|
89
|
+
(space? >> or_op.as(:operator) >>
|
90
|
+
space? >> and_expression.as(:right)
|
91
|
+
).repeat(1).as(:operations).maybe
|
92
|
+
end
|
93
|
+
|
94
|
+
rule(:expression) do
|
95
|
+
or_expression
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Basic101
|
2
|
+
|
3
|
+
class Parser < Parslet::Parser
|
4
|
+
|
5
|
+
rule(:for_statement) do
|
6
|
+
str('FOR') >>
|
7
|
+
space? >> scalar_reference.as(:reference) >>
|
8
|
+
space? >> str('=') >>
|
9
|
+
space? >> expression.as(:from) >>
|
10
|
+
space? >> str('TO') >>
|
11
|
+
space? >> expression.as(:to) >>
|
12
|
+
(space? >> str('STEP') >> space? >> expression).maybe.as(:step)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Basic101
|
2
|
+
|
3
|
+
class Parser < Parslet::Parser
|
4
|
+
|
5
|
+
rule(:identifier) do
|
6
|
+
string_identifier | numeric_identifier
|
7
|
+
end
|
8
|
+
|
9
|
+
rule(:numeric_identifier) do
|
10
|
+
base_identifier.as(:numeric_identifier)
|
11
|
+
end
|
12
|
+
|
13
|
+
rule(:string_identifier) do
|
14
|
+
(base_identifier >> str('$')).as(:string_identifier)
|
15
|
+
end
|
16
|
+
|
17
|
+
rule(:function_identifier) do
|
18
|
+
user_defined_function_identifier |
|
19
|
+
built_in_function_identifier
|
20
|
+
end
|
21
|
+
|
22
|
+
rule(:user_defined_function_identifier) do
|
23
|
+
(str('FN') >> base_identifier >>
|
24
|
+
str('$').maybe).as(:function_identifier)
|
25
|
+
end
|
26
|
+
|
27
|
+
rule(:built_in_function_identifier) do
|
28
|
+
(str('ABS') |
|
29
|
+
str('ASC') |
|
30
|
+
str('CHR$') |
|
31
|
+
str('COS') |
|
32
|
+
str('EXP') |
|
33
|
+
str('INT') |
|
34
|
+
str('LEFT$') |
|
35
|
+
str('LEN') |
|
36
|
+
str('LOG') |
|
37
|
+
str('MID$') |
|
38
|
+
str('RIGHT$') |
|
39
|
+
str('RND') |
|
40
|
+
str('SGN') |
|
41
|
+
str('SIN') |
|
42
|
+
str('SQR') |
|
43
|
+
str('STR$') |
|
44
|
+
str('TAB') |
|
45
|
+
str('TAN') |
|
46
|
+
str('VAL')).as(:function_identifier)
|
47
|
+
end
|
48
|
+
|
49
|
+
rule(:base_identifier) do
|
50
|
+
(keyword.absent? >> match('[A-Z]')) >>
|
51
|
+
(keyword.absent? >> match('[A-Z0-9]')).repeat(0)
|
52
|
+
end
|
53
|
+
|
54
|
+
rule(:keyword) do
|
55
|
+
str('AND') |
|
56
|
+
str('DATA') |
|
57
|
+
str('DEF') |
|
58
|
+
str('DIM') |
|
59
|
+
str('ELSE') |
|
60
|
+
str('ELSE') |
|
61
|
+
str('END') |
|
62
|
+
str('FOR') |
|
63
|
+
str('GOSUB') |
|
64
|
+
str('GOTO') |
|
65
|
+
str('GOTO') |
|
66
|
+
str('IF') |
|
67
|
+
str('INPUT') |
|
68
|
+
str('LET') |
|
69
|
+
str('NEXT') |
|
70
|
+
str('NOT') |
|
71
|
+
str('ON') |
|
72
|
+
str('OR') |
|
73
|
+
str('PRINT') |
|
74
|
+
str('RANDOMIZE') |
|
75
|
+
str('READ') |
|
76
|
+
str('REM') |
|
77
|
+
str('RESTORE') |
|
78
|
+
str('RETURN') |
|
79
|
+
str('STEP') |
|
80
|
+
str('STOP') |
|
81
|
+
str('THEN') |
|
82
|
+
str('TO')
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Basic101
|
2
|
+
|
3
|
+
class Parser < Parslet::Parser
|
4
|
+
|
5
|
+
rule(:if_statement) do
|
6
|
+
str('IF').as(:if) >>
|
7
|
+
space? >> expression.as(:condition) >>
|
8
|
+
(space? >> str('THEN')).maybe >>
|
9
|
+
space? >> if_block.as(:then_block) >>
|
10
|
+
(space? >> str('ELSE') >> space? >> if_block).maybe.as(:else_block)
|
11
|
+
end
|
12
|
+
|
13
|
+
rule(:if_block) do
|
14
|
+
(integer.as(:if_line_number) |
|
15
|
+
statements)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Basic101
|
2
|
+
|
3
|
+
class Parser < Parslet::Parser
|
4
|
+
|
5
|
+
rule(:input_statement) do
|
6
|
+
str('INPUT').as(:input) >>
|
7
|
+
(space? >> quoted_string.as(:prompt) >>
|
8
|
+
space? >> prompt_delimeter.as(:prompt_delimeter)).maybe >>
|
9
|
+
space? >> reference_list.as(:references)
|
10
|
+
end
|
11
|
+
|
12
|
+
rule(:prompt_delimeter) do
|
13
|
+
str(';').as(:prompt_delimeter) |
|
14
|
+
str(',').as(:null_prompt_delimeter)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Basic101
|
2
|
+
|
3
|
+
class Parser < Parslet::Parser
|
4
|
+
|
5
|
+
rule(:float) do
|
6
|
+
(fixed >> exponent.maybe |
|
7
|
+
sign.maybe >> decimal >> exponent).as(:float)
|
8
|
+
end
|
9
|
+
|
10
|
+
rule(:integer) do
|
11
|
+
(sign.maybe >> decimal).as(:integer)
|
12
|
+
end
|
13
|
+
|
14
|
+
rule(:decimal) do
|
15
|
+
match('[0-9]').repeat(1)
|
16
|
+
end
|
17
|
+
|
18
|
+
rule(:sign) do
|
19
|
+
match('[+-]')
|
20
|
+
end
|
21
|
+
|
22
|
+
rule(:fixed) do
|
23
|
+
sign.maybe >>
|
24
|
+
(decimal >> str('.') >> decimal.maybe) |
|
25
|
+
(str('.') >> decimal)
|
26
|
+
end
|
27
|
+
|
28
|
+
rule(:exponent) do
|
29
|
+
str('E') >> sign.maybe >> decimal
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Basic101
|
2
|
+
|
3
|
+
class Parser < Parslet::Parser
|
4
|
+
|
5
|
+
rule(:on_goto_statement) do
|
6
|
+
str('ON').as(:on_goto) >>
|
7
|
+
space? >>expression.as(:expression) >>
|
8
|
+
space? >> str('GOTO') >>
|
9
|
+
(
|
10
|
+
space? >> integer >>
|
11
|
+
(
|
12
|
+
space? >> str(',') >>
|
13
|
+
space? >> integer
|
14
|
+
).repeat(0)
|
15
|
+
).as(:line_numbers)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|