Commit current state
This commit is contained in:
parent
bacd68d1d9
commit
7a8b3f9c43
1
Gemfile
1
Gemfile
@ -1,3 +1,4 @@
|
||||
source "https://rubygems.org"
|
||||
gem "rexical"
|
||||
gem "racc"
|
||||
gem "rake"
|
||||
|
@ -2,6 +2,7 @@ GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
racc (1.4.14)
|
||||
rake (12.3.2)
|
||||
rexical (1.0.5)
|
||||
|
||||
PLATFORMS
|
||||
@ -9,6 +10,7 @@ PLATFORMS
|
||||
|
||||
DEPENDENCIES
|
||||
racc
|
||||
rake
|
||||
rexical
|
||||
|
||||
BUNDLED WITH
|
||||
|
7
Rakefile
Normal file
7
Rakefile
Normal file
@ -0,0 +1,7 @@
|
||||
task :default => ["lexer.rb","parser.rb"]
|
||||
file "lexer.rb" => ["lexer.rex"] do
|
||||
`rex lexer.rex -o lexer.rb`
|
||||
end
|
||||
file "parser.rb" => ["parser.y"] do
|
||||
`racc parser.y -o parser.rb`
|
||||
end
|
196
compiler
Executable file
196
compiler
Executable file
@ -0,0 +1,196 @@
|
||||
#! /usr/bin/env ruby
|
||||
`rake`
|
||||
require "./parser.rb"
|
||||
$indx_map=-8
|
||||
$var_map={}
|
||||
$tab_level=-1
|
||||
def generate_expr(expression)
|
||||
$tab_level+=1
|
||||
$tab_level.times do
|
||||
print "-"
|
||||
end
|
||||
code=""
|
||||
p expression
|
||||
case expression[:type]
|
||||
when :number
|
||||
code+="mov rax,#{expression[:value]}\n"
|
||||
when :neg
|
||||
code+=generate_expr(expression[:expr])
|
||||
code+="neg rax\n"
|
||||
when :comp
|
||||
code+=generate_expr(expression[:expr])
|
||||
code+="not rax\n"
|
||||
when :lneg
|
||||
code+=generate_expr(expression[:expr])
|
||||
code+="cmp rax,0\n"
|
||||
code+="mov rax,0\n"
|
||||
code+="sete al\n"
|
||||
when :var
|
||||
code+="mov rax,[rbp#{$var_map[expression[:name]][1]}]\n"
|
||||
when :assign
|
||||
code+=generate_expr(expression[:expr])
|
||||
code+="mov [rbp#{$var_map[expression[:name]][1]}],rax\n"
|
||||
when :comma
|
||||
code+=generate_expr(expression[:expr1])
|
||||
code+=generate_expr(expression[:expr2])
|
||||
when :seteq
|
||||
expression[:type]=expression[:op]
|
||||
name=expression[:name]
|
||||
expression.delete :op
|
||||
expression.delete :name
|
||||
code+=generate_expr({:type=>:assign,:name=>name,:expr=>expression})
|
||||
else
|
||||
code+=generate_expr(expression[:expr1])
|
||||
code+="push rax\n"
|
||||
code+=generate_expr(expression[:expr2])
|
||||
code+="pop rcx\n"
|
||||
case expression[:type]
|
||||
when :plus
|
||||
code+="add rax,rcx\n"
|
||||
when :minus
|
||||
code+="push rax\n"
|
||||
code+="push rcx\n"
|
||||
code+="pop rax\n"
|
||||
code+="pop rcx\n"
|
||||
code+="sub rax,rcx\n"
|
||||
when :mul
|
||||
code+="imul rax,rcx\n"
|
||||
when :div
|
||||
code+="push rax\n"
|
||||
code+="push rcx\n"
|
||||
code+="pop rax\n"
|
||||
code+="pop rcx\n"
|
||||
code+="mov edx,0\n"
|
||||
code+="idiv ecx\n"
|
||||
when :mod
|
||||
code+="push rax\n"
|
||||
code+="push rcx\n"
|
||||
code+="pop rax\n"
|
||||
code+="pop rcx\n"
|
||||
code+="mov edx,0\n"
|
||||
code+="idiv ecx\n"
|
||||
code+="mov eax,edx\n"
|
||||
when :eq
|
||||
code+="cmp rax,rcx\n"
|
||||
code+="mov rax,0\n"
|
||||
code+="sete al\n"
|
||||
when :ne
|
||||
code+="cmp rax,rcx\n"
|
||||
code+="mov rax,0\n"
|
||||
code+="setne al\n"
|
||||
when :ge
|
||||
code+="cmp rax,rcx\n"
|
||||
code+="mov rax,0\n"
|
||||
code+="setge al\n"
|
||||
when :le
|
||||
code+="cmp rax,rcx\n"
|
||||
code+="mov rax,0\n"
|
||||
code+="setle al\n"
|
||||
when :gt
|
||||
code+="cmp rax,rcx\n"
|
||||
code+="mov rax,0\n"
|
||||
code+="setgt al\n"
|
||||
when :lt
|
||||
code+="cmp rax,rcx\n"
|
||||
code+="mov rax,0\n"
|
||||
code+="setlt al\n"
|
||||
when :lor
|
||||
code+="or eax,ecx\n"
|
||||
code+="mov eax,0\n"
|
||||
code+="setne al\n"
|
||||
when :land
|
||||
code+="cmp ecx,0\n"
|
||||
code+="setne cl\n"
|
||||
code+="cmp eax,0\n"
|
||||
code+="mov eax,0\n"
|
||||
code+="setne al\n"
|
||||
code+="and al,cl\n"
|
||||
when :shl
|
||||
code+="push rax\n"
|
||||
code+="push rcx\n"
|
||||
code+="pop rax\n"
|
||||
code+="pop rcx\n"
|
||||
code+="shl rax,cl\n"
|
||||
when :shr
|
||||
code+="push rax\n"
|
||||
code+="push rcx\n"
|
||||
code+="pop rax\n"
|
||||
code+="pop rcx\n"
|
||||
code+="shr rax,cl\n"
|
||||
when :and
|
||||
code+="and rax,rcx\n"
|
||||
when :or
|
||||
code+="or rax,rcx\n"
|
||||
when :xor
|
||||
code+="xor rax,rcx\n"
|
||||
end
|
||||
end
|
||||
$tab_level-=1
|
||||
return code
|
||||
end
|
||||
def generate_statement(statement)
|
||||
$tab_level+=1
|
||||
$tab_level.times do
|
||||
print "-"
|
||||
end
|
||||
p statement
|
||||
code=""
|
||||
case statement[:type]
|
||||
when :return
|
||||
code+=generate_expr(statement[:expr])
|
||||
code+="mov rsp,rbp\n"
|
||||
code+="pop rbp\n"
|
||||
code+="ret\n"
|
||||
when :vardecl
|
||||
code+="push 0\n"
|
||||
$var_map[statement[:varname]]=[statement[:vartype],$indx]
|
||||
$indx-=8
|
||||
when :vardeclinit
|
||||
code+=generate_expr(statement[:init])
|
||||
code+="push rax\n"
|
||||
$var_map[statement[:varname]]=[statement[:vartype],$indx]
|
||||
$indx-=8
|
||||
when :expr
|
||||
code+=generate_expr(statement[:expr])
|
||||
end
|
||||
$tab_level-=1;
|
||||
return code
|
||||
end
|
||||
def generate_block(block)
|
||||
code=""
|
||||
for statement in block
|
||||
code+=generate_statement(statement)
|
||||
end
|
||||
return code
|
||||
end
|
||||
def generate_func(func)
|
||||
code=""
|
||||
$indx=-8
|
||||
$var_map={}
|
||||
code+=".globl _#{func[:name]}\n"
|
||||
code+="_#{func[:name]}:\n"
|
||||
code+="push rbp\n"
|
||||
code+="mov rbp,rsp\n"
|
||||
code+=generate_block(func[:code])
|
||||
code+="mov rax,0\n"
|
||||
code+="mov rsp,rbp\n"
|
||||
code+="pop rbp\n"
|
||||
code+="ret\n"
|
||||
return code
|
||||
end
|
||||
def generate(ast)
|
||||
code=""
|
||||
for func in ast
|
||||
code+=generate_func(func)
|
||||
end
|
||||
return code
|
||||
end
|
||||
program=File.read("main.c")
|
||||
p CX86.new.tokenize(program)
|
||||
ast=CX86.new.parse(program)
|
||||
code=generate(ast)
|
||||
#puts code
|
||||
f=File.open("out.asm","w")
|
||||
f.puts code
|
||||
f.close
|
||||
puts `gcc -masm=intel -o out out.asm;./out;echo $?`
|
205
lexer.rb
Normal file
205
lexer.rb
Normal file
@ -0,0 +1,205 @@
|
||||
#--
|
||||
# DO NOT MODIFY!!!!
|
||||
# This file is automatically generated by rex 1.0.5
|
||||
# from lexical definition file "lexer.rex".
|
||||
#++
|
||||
|
||||
require 'racc/parser'
|
||||
class CX86 < Racc::Parser
|
||||
require 'strscan'
|
||||
|
||||
class ScanError < StandardError ; end
|
||||
|
||||
attr_reader :lineno
|
||||
attr_reader :filename
|
||||
attr_accessor :state
|
||||
|
||||
def scan_setup(str)
|
||||
@ss = StringScanner.new(str)
|
||||
@lineno = 1
|
||||
@state = nil
|
||||
end
|
||||
|
||||
def action
|
||||
yield
|
||||
end
|
||||
|
||||
def scan_str(str)
|
||||
scan_setup(str)
|
||||
do_parse
|
||||
end
|
||||
alias :scan :scan_str
|
||||
|
||||
def load_file( filename )
|
||||
@filename = filename
|
||||
open(filename, "r") do |f|
|
||||
scan_setup(f.read)
|
||||
end
|
||||
end
|
||||
|
||||
def scan_file( filename )
|
||||
load_file(filename)
|
||||
do_parse
|
||||
end
|
||||
|
||||
|
||||
def next_token
|
||||
return if @ss.eos?
|
||||
|
||||
# skips empty actions
|
||||
until token = _next_token or @ss.eos?; end
|
||||
token
|
||||
end
|
||||
|
||||
def _next_token
|
||||
text = @ss.peek(1)
|
||||
@lineno += 1 if text == "\n"
|
||||
token = case @state
|
||||
when nil
|
||||
case
|
||||
when (text = @ss.scan(/int/))
|
||||
action {[:TYPE,:INT]}
|
||||
|
||||
when (text = @ss.scan(/\(/))
|
||||
action {[:OPEN_PAREN,"("]}
|
||||
|
||||
when (text = @ss.scan(/\)/))
|
||||
action {[:CLOSE_PAREN,")"]}
|
||||
|
||||
when (text = @ss.scan(/\{/))
|
||||
action {[:OPEN_CURLY,"{"]}
|
||||
|
||||
when (text = @ss.scan(/\}/))
|
||||
action {[:CLOSE_CURLY,"}"]}
|
||||
|
||||
when (text = @ss.scan(/;/))
|
||||
action {[:SEMICOLON,";"]}
|
||||
|
||||
when (text = @ss.scan(/-/))
|
||||
action {[:MINUS,"-"]}
|
||||
|
||||
when (text = @ss.scan(/~/))
|
||||
action {[:COMP,"~"]}
|
||||
|
||||
when (text = @ss.scan(/!/))
|
||||
action {[:LNEG,"!"]}
|
||||
|
||||
when (text = @ss.scan(/\+=/))
|
||||
action {[:SETEQ,:plus]}
|
||||
|
||||
when (text = @ss.scan(/\-\=/))
|
||||
action {[:SETEQ,:minus]}
|
||||
|
||||
when (text = @ss.scan(/\/\=/))
|
||||
action {[:SETEQ,:mul]}
|
||||
|
||||
when (text = @ss.scan(/\*\=/))
|
||||
action {[:SETEQ,:div]}
|
||||
|
||||
when (text = @ss.scan(/\%\=/))
|
||||
action {[:SETEQ,:mod]}
|
||||
|
||||
when (text = @ss.scan(/\<\<\=/))
|
||||
action {[:SETEQ,:shl]}
|
||||
|
||||
when (text = @ss.scan(/\>\>\=/))
|
||||
action {[:SETEQ,:shr]}
|
||||
|
||||
when (text = @ss.scan(/\&\=/))
|
||||
action {[:SETEQ,:and]}
|
||||
|
||||
when (text = @ss.scan(/\|\=/))
|
||||
action {[:SETEQ,:or]}
|
||||
|
||||
when (text = @ss.scan(/\^\=/))
|
||||
action {[:SETEQ,:xor]}
|
||||
|
||||
when (text = @ss.scan(/\+/))
|
||||
action {[:PLUS,"+"]}
|
||||
|
||||
when (text = @ss.scan(/\*/))
|
||||
action {[:MUL,"*"]}
|
||||
|
||||
when (text = @ss.scan(/\//))
|
||||
action {[:DIV,"/"]}
|
||||
|
||||
when (text = @ss.scan(/%/))
|
||||
action {[:MOD,"%"]}
|
||||
|
||||
when (text = @ss.scan(/\&/))
|
||||
action {[:AND,"&"]}
|
||||
|
||||
when (text = @ss.scan(/\|/))
|
||||
action {[:OR,"|"]}
|
||||
|
||||
when (text = @ss.scan(/\^/))
|
||||
action {[:XOR,"^"]}
|
||||
|
||||
when (text = @ss.scan(/<</))
|
||||
action {[:SHL,"<<"]}
|
||||
|
||||
when (text = @ss.scan(/>>/))
|
||||
action {[:SHR,">>"]}
|
||||
|
||||
when (text = @ss.scan(/\&\&/))
|
||||
action {[:LAND,"&&"]}
|
||||
|
||||
when (text = @ss.scan(/\|\|/))
|
||||
action {[:LOR,"||"]}
|
||||
|
||||
when (text = @ss.scan(/\=\=/))
|
||||
action {[:EQ,"=="]}
|
||||
|
||||
when (text = @ss.scan(/\!\=/))
|
||||
action {[:NE,"!="]}
|
||||
|
||||
when (text = @ss.scan(/\</))
|
||||
action {[:LT,"<"]}
|
||||
|
||||
when (text = @ss.scan(/\<\=/))
|
||||
action {[:LE,"<="]}
|
||||
|
||||
when (text = @ss.scan(/\>/))
|
||||
action {[:GT,">"]}
|
||||
|
||||
when (text = @ss.scan(/\>\=/))
|
||||
action {[:GE,">="]}
|
||||
|
||||
when (text = @ss.scan(/=/))
|
||||
action {[:EQUALS,"="]}
|
||||
|
||||
when (text = @ss.scan(/,/))
|
||||
action {[:COMMA,","]}
|
||||
|
||||
when (text = @ss.scan(/return/))
|
||||
action {[:RETURN,"return"]}
|
||||
|
||||
when (text = @ss.scan(/\d+/))
|
||||
action {[:NUM,text.to_i]}
|
||||
|
||||
when (text = @ss.scan(/\w+/))
|
||||
action {[:IDENT,text]}
|
||||
|
||||
when (text = @ss.scan(/[ \t\n]+/))
|
||||
action {}
|
||||
|
||||
else
|
||||
text = @ss.string[@ss.pos .. -1]
|
||||
raise ScanError, "can not match: '" + text + "'"
|
||||
end # if
|
||||
|
||||
else
|
||||
raise ScanError, "undefined state: '" + state.to_s + "'"
|
||||
end # case state
|
||||
token
|
||||
end # def _next_token
|
||||
|
||||
def tokenize(code)
|
||||
scan_setup(code)
|
||||
tokens = []
|
||||
while token = next_token
|
||||
tokens << token
|
||||
end
|
||||
tokens
|
||||
end # class
|
||||
end
|
56
lexer.rex
Normal file
56
lexer.rex
Normal file
@ -0,0 +1,56 @@
|
||||
class CX86
|
||||
macro
|
||||
BLANK [\ \t\n]+
|
||||
rule
|
||||
int {[:TYPE,:INT]}
|
||||
\( {[:OPEN_PAREN,"("]}
|
||||
\) {[:CLOSE_PAREN,")"]}
|
||||
\{ {[:OPEN_CURLY,"{"]}
|
||||
\} {[:CLOSE_CURLY,"}"]}
|
||||
; {[:SEMICOLON,";"]}
|
||||
- {[:MINUS,"-"]}
|
||||
~ {[:COMP,"~"]}
|
||||
! {[:LNEG,"!"]}
|
||||
\+= {[:SETEQ,:plus]}
|
||||
\-\= {[:SETEQ,:minus]}
|
||||
\/\= {[:SETEQ,:mul]}
|
||||
\*\= {[:SETEQ,:div]}
|
||||
\%\= {[:SETEQ,:mod]}
|
||||
\<\<\= {[:SETEQ,:shl]}
|
||||
\>\>\= {[:SETEQ,:shr]}
|
||||
\&\= {[:SETEQ,:and]}
|
||||
\|\= {[:SETEQ,:or]}
|
||||
\^\= {[:SETEQ,:xor]}
|
||||
\+ {[:PLUS,"+"]}
|
||||
\* {[:MUL,"*"]}
|
||||
\/ {[:DIV,"/"]}
|
||||
% {[:MOD,"%"]}
|
||||
\& {[:AND,"&"]}
|
||||
\| {[:OR,"|"]}
|
||||
\^ {[:XOR,"^"]}
|
||||
<< {[:SHL,"<<"]}
|
||||
>> {[:SHR,">>"]}
|
||||
\&\& {[:LAND,"&&"]}
|
||||
\|\| {[:LOR,"||"]}
|
||||
\=\= {[:EQ,"=="]}
|
||||
\!\= {[:NE,"!="]}
|
||||
\< {[:LT,"<"]}
|
||||
\<\= {[:LE,"<="]}
|
||||
\> {[:GT,">"]}
|
||||
\>\= {[:GE,">="]}
|
||||
= {[:EQUALS,"="]}
|
||||
, {[:COMMA,","]}
|
||||
return {[:RETURN,"return"]}
|
||||
\d+ {[:NUM,text.to_i]}
|
||||
\w+ {[:IDENT,text]}
|
||||
{BLANK} {}
|
||||
inner
|
||||
def tokenize(code)
|
||||
scan_setup(code)
|
||||
tokens = []
|
||||
while token = next_token
|
||||
tokens << token
|
||||
end
|
||||
tokens
|
||||
end
|
||||
end
|
20
out.asm
Normal file
20
out.asm
Normal file
@ -0,0 +1,20 @@
|
||||
.globl _main
|
||||
_main:
|
||||
push rbp
|
||||
mov rbp,rsp
|
||||
mov rax,2
|
||||
push rax
|
||||
mov rax,[rbp-8]
|
||||
push rax
|
||||
mov rax,2
|
||||
pop rcx
|
||||
add rax,rcx
|
||||
mov [rbp-8],rax
|
||||
mov rax,[rbp-8]
|
||||
mov rsp,rbp
|
||||
pop rbp
|
||||
ret
|
||||
mov rax,0
|
||||
mov rsp,rbp
|
||||
pop rbp
|
||||
ret
|
593
parser.rb
Normal file
593
parser.rb
Normal file
@ -0,0 +1,593 @@
|
||||
#
|
||||
# DO NOT MODIFY!!!!
|
||||
# This file is automatically generated by Racc 1.4.14
|
||||
# from Racc grammer file "".
|
||||
#
|
||||
|
||||
require 'racc/parser.rb'
|
||||
|
||||
require "./lexer.rb"
|
||||
|
||||
class CX86 < Racc::Parser
|
||||
|
||||
module_eval(<<'...end parser.y/module_eval...', 'parser.y', 59)
|
||||
def initialize()
|
||||
@yydebug=true
|
||||
end
|
||||
def parse(input)
|
||||
scan_str(input)
|
||||
end
|
||||
...end parser.y/module_eval...
|
||||
##### State transition tables begin ###
|
||||
|
||||
racc_action_table = [
|
||||
15, 22, 21, 71, 63, 47, 14, 39, 67, 17,
|
||||
18, 19, 20, 15, 22, 21, 54, 55, 40, 14,
|
||||
93, 36, 17, 18, 19, 20, 22, 21, 48, 33,
|
||||
22, 21, 41, 41, 17, 18, 19, 20, 17, 18,
|
||||
19, 20, 33, 41, 53, 41, 41, 53, 54, 55,
|
||||
52, 22, 21, 52, 33, 22, 21, 41, 33, 17,
|
||||
18, 19, 20, 17, 18, 19, 20, 22, 21, 56,
|
||||
57, 58, 59, 60, 61, 17, 18, 19, 20, 33,
|
||||
22, 21, 41, 33, 56, 57, 58, 59, 17, 18,
|
||||
19, 20, 43, 21, 11, 33, 43, 21, 68, 69,
|
||||
17, 18, 19, 20, 17, 18, 19, 20, 33, 43,
|
||||
21, 54, 55, 43, 21, 54, 55, 17, 18, 19,
|
||||
20, 17, 18, 19, 20, 43, 21, 54, 55, 43,
|
||||
21, 60, 61, 17, 18, 19, 20, 17, 18, 19,
|
||||
20, 43, 21, 9, 8, 43, 21, 7, 63, 17,
|
||||
18, 19, 20, 17, 18, 19, 20, 43, 21, 64,
|
||||
3, 43, 21, 65, 6, 17, 18, 19, 20, 17,
|
||||
18, 19, 20, 43, 21, 3, 4, 43, 21, 62,
|
||||
66, 17, 18, 19, 20, 17, 18, 19, 20, 43,
|
||||
21, 65, 64, 43, 21, 62, nil, 17, 18, 19,
|
||||
20, 17, 18, 19, 20, 43, 21, nil, nil, 43,
|
||||
21, nil, nil, 17, 18, 19, 20, 17, 18, 19,
|
||||
20, 43, 21, nil, nil, 43, 21, nil, nil, 17,
|
||||
18, 19, 20, 17, 18, 19, 20, 43, 21, nil,
|
||||
nil, 43, 21, nil, nil, 17, 18, 19, 20, 17,
|
||||
18, 19, 20, 43, 21, 56, 57, 58, 59, 53,
|
||||
nil, 17, 18, 19, 20, 52, 49, 50, 51, 49,
|
||||
50, 51, 49, 50, 51 ]
|
||||
|
||||
racc_action_check = [
|
||||
13, 13, 13, 46, 30, 22, 13, 15, 38, 13,
|
||||
13, 13, 13, 11, 11, 11, 83, 83, 16, 11,
|
||||
92, 12, 11, 11, 11, 11, 69, 69, 22, 13,
|
||||
48, 48, 46, 38, 69, 69, 69, 69, 48, 48,
|
||||
48, 48, 11, 16, 79, 92, 70, 80, 26, 26,
|
||||
79, 47, 47, 80, 69, 21, 21, 72, 48, 47,
|
||||
47, 47, 47, 21, 21, 21, 21, 14, 14, 85,
|
||||
85, 85, 85, 28, 28, 14, 14, 14, 14, 47,
|
||||
41, 41, 73, 21, 27, 27, 27, 27, 41, 41,
|
||||
41, 41, 56, 56, 9, 14, 58, 58, 39, 39,
|
||||
56, 56, 56, 56, 58, 58, 58, 58, 41, 59,
|
||||
59, 81, 81, 60, 60, 82, 82, 59, 59, 59,
|
||||
59, 60, 60, 60, 60, 66, 66, 84, 84, 18,
|
||||
18, 87, 87, 66, 66, 66, 66, 18, 18, 18,
|
||||
18, 19, 19, 8, 6, 20, 20, 4, 89, 19,
|
||||
19, 19, 19, 20, 20, 20, 20, 61, 61, 90,
|
||||
0, 49, 49, 91, 3, 61, 61, 61, 61, 49,
|
||||
49, 49, 49, 50, 50, 2, 1, 51, 51, 88,
|
||||
33, 50, 50, 50, 50, 51, 51, 51, 51, 52,
|
||||
52, 32, 31, 53, 53, 29, nil, 52, 52, 52,
|
||||
52, 53, 53, 53, 53, 54, 54, nil, nil, 55,
|
||||
55, nil, nil, 54, 54, 54, 54, 55, 55, 55,
|
||||
55, 57, 57, nil, nil, 65, 65, nil, nil, 57,
|
||||
57, 57, 57, 65, 65, 65, 65, 64, 64, nil,
|
||||
nil, 63, 63, nil, nil, 64, 64, 64, 64, 63,
|
||||
63, 63, 63, 62, 62, 86, 86, 86, 86, 25,
|
||||
nil, 62, 62, 62, 62, 25, 24, 24, 24, 77,
|
||||
77, 77, 78, 78, 78 ]
|
||||
|
||||
racc_action_pointer = [
|
||||
158, 176, 173, 161, 147, nil, 140, nil, 138, 88,
|
||||
nil, 11, 14, -2, 64, 4, 9, nil, 126, 138,
|
||||
142, 52, -5, nil, 251, 247, 29, 63, 48, 168,
|
||||
-24, 163, 161, 148, nil, nil, nil, nil, -1, 89,
|
||||
nil, 77, nil, nil, nil, nil, -2, 48, 27, 158,
|
||||
170, 174, 186, 190, 202, 206, 89, 218, 93, 106,
|
||||
110, 154, 250, 238, 234, 222, 122, nil, nil, 23,
|
||||
12, nil, 23, 48, nil, nil, nil, 254, 257, 32,
|
||||
35, 92, 96, -3, 108, 48, 234, 106, 152, 120,
|
||||
130, 133, 11, nil ]
|
||||
|
||||
racc_action_default = [
|
||||
-50, -50, -1, -50, -50, -2, -50, 94, -50, -50,
|
||||
-3, -50, -50, -5, -50, -50, -50, -11, -50, -50,
|
||||
-50, -50, -16, -17, -21, -24, -27, -32, -35, -37,
|
||||
-39, -41, -43, -50, -45, -48, -4, -6, -50, -50,
|
||||
-10, -50, -12, -16, -13, -14, -50, -50, -50, -50,
|
||||
-50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
|
||||
-50, -50, -50, -50, -50, -50, -50, -7, -8, -50,
|
||||
-49, -15, -46, -47, -18, -19, -20, -22, -23, -25,
|
||||
-26, -28, -29, -30, -31, -33, -34, -36, -38, -40,
|
||||
-42, -44, -50, -9 ]
|
||||
|
||||
racc_goto_table = [
|
||||
38, 1, 88, 5, 42, 44, 45, 46, 81, 82,
|
||||
83, 84, 12, 89, 37, 79, 80, 85, 86, 77,
|
||||
78, 90, 91, 10, 87, nil, nil, 70, nil, nil,
|
||||
nil, nil, nil, 72, 73, 74, 75, 76, nil, nil,
|
||||
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
||||
nil, nil, nil, nil, nil, 92 ]
|
||||
|
||||
racc_goto_check = [
|
||||
6, 1, 13, 1, 7, 7, 7, 6, 10, 10,
|
||||
10, 10, 4, 14, 4, 9, 9, 11, 11, 8,
|
||||
8, 15, 16, 3, 12, nil, nil, 6, nil, nil,
|
||||
nil, nil, nil, 6, 6, 7, 7, 7, nil, nil,
|
||||
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
||||
nil, nil, nil, nil, nil, 6 ]
|
||||
|
||||
racc_goto_pointer = [
|
||||
nil, 1, nil, 14, 1, nil, -14, -14, -33, -39,
|
||||
-48, -43, -38, -61, -51, -44, -44, nil, nil ]
|
||||
|
||||
racc_goto_default = [
|
||||
nil, nil, 2, nil, nil, 13, 16, 23, 24, 25,
|
||||
26, 27, 28, 29, 30, 31, 32, 34, 35 ]
|
||||
|
||||
racc_reduce_table = [
|
||||
0, 0, :racc_error,
|
||||
1, 36, :_reduce_1,
|
||||
2, 36, :_reduce_2,
|
||||
5, 37, :_reduce_3,
|
||||
3, 38, :_reduce_4,
|
||||
1, 39, :_reduce_5,
|
||||
2, 39, :_reduce_6,
|
||||
3, 40, :_reduce_7,
|
||||
3, 40, :_reduce_8,
|
||||
5, 40, :_reduce_9,
|
||||
2, 40, :_reduce_10,
|
||||
1, 42, :_reduce_11,
|
||||
2, 42, :_reduce_12,
|
||||
2, 42, :_reduce_13,
|
||||
2, 42, :_reduce_14,
|
||||
3, 42, :_reduce_15,
|
||||
1, 42, :_reduce_16,
|
||||
1, 43, :_reduce_none,
|
||||
3, 43, :_reduce_18,
|
||||
3, 43, :_reduce_19,
|
||||
3, 43, :_reduce_20,
|
||||
1, 44, :_reduce_none,
|
||||
3, 44, :_reduce_22,
|
||||
3, 44, :_reduce_23,
|
||||
1, 45, :_reduce_none,
|
||||
3, 45, :_reduce_25,
|
||||
3, 45, :_reduce_26,
|
||||
1, 46, :_reduce_none,
|
||||
3, 46, :_reduce_28,
|
||||
3, 46, :_reduce_29,
|
||||
3, 46, :_reduce_30,
|
||||
3, 46, :_reduce_31,
|
||||
1, 47, :_reduce_none,
|
||||
3, 47, :_reduce_33,
|
||||
3, 47, :_reduce_34,
|
||||
1, 48, :_reduce_none,
|
||||
3, 48, :_reduce_36,
|
||||
1, 49, :_reduce_none,
|
||||
3, 49, :_reduce_38,
|
||||
1, 50, :_reduce_none,
|
||||
3, 50, :_reduce_40,
|
||||
1, 51, :_reduce_none,
|
||||
3, 51, :_reduce_42,
|
||||
1, 52, :_reduce_none,
|
||||
3, 52, :_reduce_44,
|
||||
1, 53, :_reduce_none,
|
||||
3, 53, :_reduce_46,
|
||||
3, 53, :_reduce_47,
|
||||
1, 41, :_reduce_none,
|
||||
3, 41, :_reduce_49 ]
|
||||
|
||||
racc_reduce_n = 50
|
||||
|
||||
racc_shift_n = 94
|
||||
|
||||
racc_token_table = {
|
||||
false => 0,
|
||||
:error => 1,
|
||||
:TYPE => 2,
|
||||
:IDENT => 3,
|
||||
:OPEN_PAREN => 4,
|
||||
:CLOSE_PAREN => 5,
|
||||
:OPEN_CURLY => 6,
|
||||
:CLOSE_CURLY => 7,
|
||||
:RETURN => 8,
|
||||
:SEMICOLON => 9,
|
||||
:EQUALS => 10,
|
||||
:NUM => 11,
|
||||
:MINUS => 12,
|
||||
:COMP => 13,
|
||||
:LNEG => 14,
|
||||
:MUL => 15,
|
||||
:DIV => 16,
|
||||
:MOD => 17,
|
||||
:PLUS => 18,
|
||||
:SHL => 19,
|
||||
:SHR => 20,
|
||||
:LT => 21,
|
||||
:GT => 22,
|
||||
:LE => 23,
|
||||
:GE => 24,
|
||||
:NE => 25,
|
||||
:EQ => 26,
|
||||
:AND => 27,
|
||||
:XOR => 28,
|
||||
:OR => 29,
|
||||
:LAND => 30,
|
||||
:exp => 31,
|
||||
:LOR => 32,
|
||||
:SETEQ => 33,
|
||||
:COMMA => 34 }
|
||||
|
||||
racc_nt_base = 35
|
||||
|
||||
racc_use_result_var = true
|
||||
|
||||
Racc_arg = [
|
||||
racc_action_table,
|
||||
racc_action_check,
|
||||
racc_action_default,
|
||||
racc_action_pointer,
|
||||
racc_goto_table,
|
||||
racc_goto_check,
|
||||
racc_goto_default,
|
||||
racc_goto_pointer,
|
||||
racc_nt_base,
|
||||
racc_reduce_table,
|
||||
racc_token_table,
|
||||
racc_shift_n,
|
||||
racc_reduce_n,
|
||||
racc_use_result_var ]
|
||||
|
||||
Racc_token_to_s_table = [
|
||||
"$end",
|
||||
"error",
|
||||
"TYPE",
|
||||
"IDENT",
|
||||
"OPEN_PAREN",
|
||||
"CLOSE_PAREN",
|
||||
"OPEN_CURLY",
|
||||
"CLOSE_CURLY",
|
||||
"RETURN",
|
||||
"SEMICOLON",
|
||||
"EQUALS",
|
||||
"NUM",
|
||||
"MINUS",
|
||||
"COMP",
|
||||
"LNEG",
|
||||
"MUL",
|
||||
"DIV",
|
||||
"MOD",
|
||||
"PLUS",
|
||||
"SHL",
|
||||
"SHR",
|
||||
"LT",
|
||||
"GT",
|
||||
"LE",
|
||||
"GE",
|
||||
"NE",
|
||||
"EQ",
|
||||
"AND",
|
||||
"XOR",
|
||||
"OR",
|
||||
"LAND",
|
||||
"exp",
|
||||
"LOR",
|
||||
"SETEQ",
|
||||
"COMMA",
|
||||
"$start",
|
||||
"program",
|
||||
"function",
|
||||
"block",
|
||||
"statements",
|
||||
"statement",
|
||||
"expression",
|
||||
"factor",
|
||||
"term",
|
||||
"additivexp",
|
||||
"shiftexp",
|
||||
"relationalexp",
|
||||
"equalityexp",
|
||||
"andexp",
|
||||
"xorexp",
|
||||
"orexp",
|
||||
"landexp",
|
||||
"lorexp",
|
||||
"assignexp" ]
|
||||
|
||||
Racc_debug_parser = false
|
||||
|
||||
##### State transition tables end #####
|
||||
|
||||
# reduce 0 omitted
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 2)
|
||||
def _reduce_1(val, _values, result)
|
||||
result=[val[0]]
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 3)
|
||||
def _reduce_2(val, _values, result)
|
||||
result=[val[0],val[1]].flatten
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 4)
|
||||
def _reduce_3(val, _values, result)
|
||||
result={:type=>val[0],:name=>val[1],:code=>val[4]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 5)
|
||||
def _reduce_4(val, _values, result)
|
||||
result=val[1]
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 6)
|
||||
def _reduce_5(val, _values, result)
|
||||
result=[val[0]]
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 7)
|
||||
def _reduce_6(val, _values, result)
|
||||
result=[val[0],val[1]].flatten
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 8)
|
||||
def _reduce_7(val, _values, result)
|
||||
result={:type=>:return,:expr=>val[1]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 9)
|
||||
def _reduce_8(val, _values, result)
|
||||
result={:type=>:vardecl,:vartype=>val[0],:varname=>val[1]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 10)
|
||||
def _reduce_9(val, _values, result)
|
||||
result={:type=>:vardeclinit,:vartype=>val[0],:varname=>val[1],:init=>val[3]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 11)
|
||||
def _reduce_10(val, _values, result)
|
||||
result={:type=>:expr,:expr=>val[0]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 12)
|
||||
def _reduce_11(val, _values, result)
|
||||
result={:type=>:number,:value=>val[0]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 13)
|
||||
def _reduce_12(val, _values, result)
|
||||
result={:type=>:neg,:expr=>val[1]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 14)
|
||||
def _reduce_13(val, _values, result)
|
||||
result={:type=>:comp,:expr=>val[1]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 15)
|
||||
def _reduce_14(val, _values, result)
|
||||
result={:type=>:lneg,:expr=>val[1]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 16)
|
||||
def _reduce_15(val, _values, result)
|
||||
result=val[1]
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 17)
|
||||
def _reduce_16(val, _values, result)
|
||||
result={:type=>:var,:name=>val[0]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
# reduce 17 omitted
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 19)
|
||||
def _reduce_18(val, _values, result)
|
||||
result={:type=>:mul,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 20)
|
||||
def _reduce_19(val, _values, result)
|
||||
result={:type=>:div,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 21)
|
||||
def _reduce_20(val, _values, result)
|
||||
result={:type=>:mod,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
# reduce 21 omitted
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 23)
|
||||
def _reduce_22(val, _values, result)
|
||||
result={:type=>:plus,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 24)
|
||||
def _reduce_23(val, _values, result)
|
||||
result={:type=>:minus,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
# reduce 24 omitted
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 26)
|
||||
def _reduce_25(val, _values, result)
|
||||
result={:type=>:shl,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 27)
|
||||
def _reduce_26(val, _values, result)
|
||||
result={:type=>:shr,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
# reduce 27 omitted
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 29)
|
||||
def _reduce_28(val, _values, result)
|
||||
result={:type=>:lt,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 30)
|
||||
def _reduce_29(val, _values, result)
|
||||
result={:type=>:gt,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 31)
|
||||
def _reduce_30(val, _values, result)
|
||||
result={:type=>:le,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 32)
|
||||
def _reduce_31(val, _values, result)
|
||||
result={:type=>:ge,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
# reduce 32 omitted
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 34)
|
||||
def _reduce_33(val, _values, result)
|
||||
result={:type=>:ne,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 35)
|
||||
def _reduce_34(val, _values, result)
|
||||
result={:type=>:eq,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
# reduce 35 omitted
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 37)
|
||||
def _reduce_36(val, _values, result)
|
||||
result={:type=>:and,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
# reduce 37 omitted
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 39)
|
||||
def _reduce_38(val, _values, result)
|
||||
result={:type=>:xor,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
# reduce 39 omitted
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 41)
|
||||
def _reduce_40(val, _values, result)
|
||||
result={:type=>:or,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
# reduce 41 omitted
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 43)
|
||||
def _reduce_42(val, _values, result)
|
||||
result={:type=>:land,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
# reduce 43 omitted
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 45)
|
||||
def _reduce_44(val, _values, result)
|
||||
result={:type=>:lor,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
# reduce 45 omitted
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 47)
|
||||
def _reduce_46(val, _values, result)
|
||||
result={:type=>:assign,:name=>val[0],:expr=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 48)
|
||||
def _reduce_47(val, _values, result)
|
||||
result={:type=>:assign,:name=>val[0],:expr=>{:type=>val[1],:expr1=>{:type=>:var,:name=>val[0]},:expr2=>val[2]}}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
# reduce 48 omitted
|
||||
|
||||
module_eval(<<'.,.,', 'parser.y', 50)
|
||||
def _reduce_49(val, _values, result)
|
||||
result={:type=>:comma,:expr1=>val[0],:expr2=>val[2]}
|
||||
result
|
||||
end
|
||||
.,.,
|
||||
|
||||
def _reduce_none(val, _values, result)
|
||||
val[0]
|
||||
end
|
||||
|
||||
end # class CX86
|
64
parser.y
Normal file
64
parser.y
Normal file
@ -0,0 +1,64 @@
|
||||
class CX86
|
||||
rule
|
||||
program: function {result=[val[0]]}
|
||||
| function program {result=[val[0],val[1]].flatten}
|
||||
function: TYPE IDENT OPEN_PAREN CLOSE_PAREN block {result={:type=>val[0],:name=>val[1],:code=>val[4]}}
|
||||
block: OPEN_CURLY statements CLOSE_CURLY {result=val[1]}
|
||||
statements: statement {result=[val[0]]}
|
||||
| statement statements {result=[val[0],val[1]].flatten}
|
||||
statement: RETURN expression SEMICOLON {result={:type=>:return,:expr=>val[1]}}
|
||||
| TYPE IDENT SEMICOLON {result={:type=>:vardecl,:vartype=>val[0],:varname=>val[1]}}
|
||||
| TYPE IDENT EQUALS expression SEMICOLON {result={:type=>:vardeclinit,:vartype=>val[0],:varname=>val[1],:init=>val[3]}}
|
||||
| expression SEMICOLON {result={:type=>:expr,:expr=>val[0]}}
|
||||
factor: NUM {result={:type=>:number,:value=>val[0]}}
|
||||
| MINUS factor {result={:type=>:neg,:expr=>val[1]}}
|
||||
| COMP factor {result={:type=>:comp,:expr=>val[1]}}
|
||||
| LNEG factor {result={:type=>:lneg,:expr=>val[1]}}
|
||||
| OPEN_PAREN expression CLOSE_PAREN {result=val[1]}
|
||||
| IDENT {result={:type=>:var,:name=>val[0]}}
|
||||
term: factor
|
||||
| term MUL factor {result={:type=>:mul,:expr1=>val[0],:expr2=>val[2]}}
|
||||
| term DIV factor {result={:type=>:div,:expr1=>val[0],:expr2=>val[2]}}
|
||||
| term MOD factor {result={:type=>:mod,:expr1=>val[0],:expr2=>val[2]}}
|
||||
additivexp: term
|
||||
| additivexp PLUS term {result={:type=>:plus,:expr1=>val[0],:expr2=>val[2]}}
|
||||
| additivexp MINUS term {result={:type=>:minus,:expr1=>val[0],:expr2=>val[2]}}
|
||||
shiftexp: additivexp
|
||||
| shiftexp SHL additivexp {result={:type=>:shl,:expr1=>val[0],:expr2=>val[2]}}
|
||||
| shiftexp SHR additivexp {result={:type=>:shr,:expr1=>val[0],:expr2=>val[2]}}
|
||||
relationalexp: shiftexp
|
||||
| relationalexp LT shiftexp {result={:type=>:lt,:expr1=>val[0],:expr2=>val[2]}}
|
||||
| relationalexp GT shiftexp {result={:type=>:gt,:expr1=>val[0],:expr2=>val[2]}}
|
||||
| relationalexp LE shiftexp {result={:type=>:le,:expr1=>val[0],:expr2=>val[2]}}
|
||||
| relationalexp GE shiftexp {result={:type=>:ge,:expr1=>val[0],:expr2=>val[2]}}
|
||||
equalityexp: relationalexp
|
||||
| equalityexp NE relationalexp {result={:type=>:ne,:expr1=>val[0],:expr2=>val[2]}}
|
||||
| equalityexp EQ relationalexp {result={:type=>:eq,:expr1=>val[0],:expr2=>val[2]}}
|
||||
andexp: equalityexp
|
||||
| andexp AND equalityexp {result={:type=>:and,:expr1=>val[0],:expr2=>val[2]}}
|
||||
xorexp: andexp
|
||||
| xorexp XOR andexp {result={:type=>:xor,:expr1=>val[0],:expr2=>val[2]}}
|
||||
orexp: xorexp
|
||||
| orexp OR xorexp {result={:type=>:or,:expr1=>val[0],:expr2=>val[2]}}
|
||||
landexp: orexp
|
||||
| landexp LAND orexp {result={:type=>:land,:expr1=>val[0],:expr2=>val[2]}}
|
||||
lorexp: landexp
|
||||
| exp LOR landexp {result={:type=>:lor,:expr1=>val[0],:expr2=>val[2]}}
|
||||
assignexp: lorexp
|
||||
| IDENT EQUALS expression {result={:type=>:assign,:name=>val[0],:expr=>val[2]}}
|
||||
| IDENT SETEQ expression {result={:type=>:assign,:name=>val[0],:expr=>{:type=>val[1],:expr1=>{:type=>:var,:name=>val[0]},:expr2=>val[2]}}}
|
||||
expression: assignexp
|
||||
| expression COMMA expression {result={:type=>:comma,:expr1=>val[0],:expr2=>val[2]}}
|
||||
|
||||
end
|
||||
|
||||
---- header
|
||||
require "./lexer.rb"
|
||||
|
||||
---- inner
|
||||
def initialize()
|
||||
@yydebug=true
|
||||
end
|
||||
def parse(input)
|
||||
scan_str(input)
|
||||
end
|
Loading…
Reference in New Issue
Block a user