keep some stuff in storage that just gets in tway in crystal
This commit is contained in:
parent
8de59a85ba
commit
8584c93575
48
unused/addr_table_object.rb
Normal file
48
unused/addr_table_object.rb
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
module Asm
|
||||||
|
module Arm
|
||||||
|
|
||||||
|
# TODO actually find the closest somehow (DROPPED for now)
|
||||||
|
def self.closest_addrtable(as)
|
||||||
|
as.values.find do |obj|
|
||||||
|
obj.is_a?(Asm::Arm::AddrTableObject)
|
||||||
|
end || (raise Asm::AssemblyError.new('could not find addrtable to use', nil))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
#this has been DROPPED for now (didn't work) and we can do without it
|
||||||
|
class AddrTableObject
|
||||||
|
def initialize
|
||||||
|
@table = []
|
||||||
|
@const = []
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO don't create new entry if there's already an entry for the same label/const
|
||||||
|
def add_label(label)
|
||||||
|
d = [label, Asm::LabelObject.new]
|
||||||
|
@table << d
|
||||||
|
d[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_const(const)
|
||||||
|
d = [const, Asm::LabelObject.new]
|
||||||
|
@const << d
|
||||||
|
d[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
def assemble(io, as)
|
||||||
|
@table.each do |pair|
|
||||||
|
target_label, here_label = *pair
|
||||||
|
here_label.assemble io, as
|
||||||
|
as.add_relocation io.tell, target_label, Asm::Arm::R_ARM_ABS32,
|
||||||
|
Asm::Arm::Instruction::RelocHandler
|
||||||
|
io.write_uint32 0
|
||||||
|
end
|
||||||
|
@const.each do |pair|
|
||||||
|
const, here_label = *pair
|
||||||
|
here_label.assemble io, as
|
||||||
|
io.write_uint32 const
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
85
unused/ast_assembler.rb
Normal file
85
unused/ast_assembler.rb
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
module Asm
|
||||||
|
class AstAssembler
|
||||||
|
def initialize(asm_arch)
|
||||||
|
@asm_arch = asm_arch
|
||||||
|
|
||||||
|
@symbols = {}
|
||||||
|
@inst_label_context = {}
|
||||||
|
|
||||||
|
@asm = Asm::Assembler.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def assembler
|
||||||
|
@asm
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_ast(ast)
|
||||||
|
label_breadcrumb = []
|
||||||
|
ast.children.each do |cmd|
|
||||||
|
if (cmd.is_a?(Asm::LabelNode))
|
||||||
|
m = /^\/+/.match(cmd.name)
|
||||||
|
count = m ? m[0].length : 0
|
||||||
|
label_breadcrumb = label_breadcrumb[0,count]
|
||||||
|
label_breadcrumb << cmd.name[count..-1]
|
||||||
|
@asm.add_value object_for_label(label_breadcrumb.join('/'))
|
||||||
|
elsif (cmd.is_a?(Asm::InstructionNode))
|
||||||
|
inst = @asm_arch::Instruction.new(cmd, self)
|
||||||
|
@asm.add_value inst
|
||||||
|
@inst_label_context[inst] = label_breadcrumb
|
||||||
|
elsif (cmd.is_a?(Asm::DirectiveNode))
|
||||||
|
if (cmd.name == 'global')
|
||||||
|
symbol_for_label(cmd.value)[:linkage] = Elf::Constants::STB_GLOBAL
|
||||||
|
elsif (cmd.name == 'extern')
|
||||||
|
object_for_label(cmd.value).extern!
|
||||||
|
elsif (cmd.name == 'hexdata')
|
||||||
|
bytes = cmd.value.strip.split(/\s+/).map do |hex|
|
||||||
|
hex.to_i(16)
|
||||||
|
end.pack('C*')
|
||||||
|
@asm.add_value Asm::StringNode.new(bytes)
|
||||||
|
elsif (cmd.name == "asciz")
|
||||||
|
str = eval(cmd.value) + "\x00"
|
||||||
|
@asm.add_value Asm::StringNode.new(str)
|
||||||
|
elsif (defined?(Asm::Arm) and cmd.name == 'addrtable')
|
||||||
|
@asm.add_value Asm::Arm::AddrTableObject.new
|
||||||
|
else
|
||||||
|
raise Asm::AssemblyError.new('unknown directive', cmd)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# instruction is user for label context
|
||||||
|
def symbol_for_label(name, instruction=nil)
|
||||||
|
if (instruction)
|
||||||
|
context = @inst_label_context[instruction]
|
||||||
|
m = /^(\/*)(.+)/.match(name)
|
||||||
|
breadcrumb = context[0,m[1].length]
|
||||||
|
breadcrumb << m[2]
|
||||||
|
qual_name = breadcrumb.join('/')
|
||||||
|
else
|
||||||
|
qual_name = name
|
||||||
|
end
|
||||||
|
|
||||||
|
if (not @symbols[qual_name])
|
||||||
|
@symbols[name] = {:label => Asm::LabelObject.new, :linkage => Elf::Constants::STB_LOCAL, :name => qual_name}
|
||||||
|
end
|
||||||
|
@symbols[qual_name]
|
||||||
|
end
|
||||||
|
|
||||||
|
def object_for_label(name, instruction=nil)
|
||||||
|
symbol_for_label(name, instruction)[:label]
|
||||||
|
end
|
||||||
|
|
||||||
|
def assemble(io)
|
||||||
|
@asm.assemble io
|
||||||
|
end
|
||||||
|
|
||||||
|
def symbols
|
||||||
|
@symbols.values
|
||||||
|
end
|
||||||
|
|
||||||
|
def relocations
|
||||||
|
@asm.relocations
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
29
unused/code_generator.rb
Normal file
29
unused/code_generator.rb
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
require "asm/arm/code_generator"
|
||||||
|
|
||||||
|
if (__FILE__ == $0)
|
||||||
|
gen = Asm::Arm::ArmAssembler.new
|
||||||
|
|
||||||
|
gen.instance_eval {
|
||||||
|
mov r0, 5
|
||||||
|
loop_start = label
|
||||||
|
loop_start.set!
|
||||||
|
subs r0, r0, 1
|
||||||
|
bne loop_start
|
||||||
|
mov r7, 1
|
||||||
|
swi 0
|
||||||
|
}
|
||||||
|
|
||||||
|
gen.add_string("printf"+ "\x00")
|
||||||
|
require 'asm/object_writer'
|
||||||
|
writer = Asm::ObjectWriter.new(Elf::Constants::TARGET_ARM)
|
||||||
|
writer.set_text gen.assemble_to_string
|
||||||
|
|
||||||
|
|
||||||
|
begin
|
||||||
|
writer.save('arm_as_generated.o')
|
||||||
|
rescue => err
|
||||||
|
puts 'as: cannot save output file: ' + err.message
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
149
unused/command_line.rb
Normal file
149
unused/command_line.rb
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
require_relative 'parser'
|
||||||
|
require_relative 'assembler'
|
||||||
|
require_relative 'objectwriter'
|
||||||
|
require 'optparse'
|
||||||
|
require 'ostruct'
|
||||||
|
|
||||||
|
module Asm
|
||||||
|
class CommandLine
|
||||||
|
def initialize
|
||||||
|
options = OpenStruct.new
|
||||||
|
options.output_file = "a.out"
|
||||||
|
options.target = :arm
|
||||||
|
|
||||||
|
opts = OptionParser.new do |opts|
|
||||||
|
opts.banner = "Usage: as [options] <input file>"
|
||||||
|
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "Options:"
|
||||||
|
|
||||||
|
opts.on("-t", "--target TARGET",
|
||||||
|
"Specify target architecture (arm [default], ttk91)") { |o|
|
||||||
|
options.target = o.to_sym
|
||||||
|
if (not [:arm, :ttk91].include?(options.target))
|
||||||
|
puts opts
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.on("-o", "--output FILENAME",
|
||||||
|
"Specify output filename for object file") { |o|
|
||||||
|
options.output_file = o
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.on("-s", "--show-ast",
|
||||||
|
"Show parse tree") { |o|
|
||||||
|
options.show_ast = true
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.on_tail("-h", "--help", "Show this message") {
|
||||||
|
puts opts
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.parse!(ARGV)
|
||||||
|
|
||||||
|
options.input_file = ARGV.shift
|
||||||
|
if (not options.input_file)
|
||||||
|
puts opts
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
|
||||||
|
@options = options
|
||||||
|
end
|
||||||
|
attr_reader :options
|
||||||
|
|
||||||
|
def run
|
||||||
|
begin
|
||||||
|
if (options.input_file == '-')
|
||||||
|
code = $stdin.read
|
||||||
|
else
|
||||||
|
code = File.read(options.input_file)
|
||||||
|
end
|
||||||
|
rescue => err
|
||||||
|
puts 'as: could not read input file: ' + err.message
|
||||||
|
exit 2
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
ast = Asm::Parser.parse(code)
|
||||||
|
rescue Asm::ParseError => err
|
||||||
|
puts 'as: parse error on line %d, column %d' % [err.line+1, err.column+1]
|
||||||
|
line = code.split("\n")[err.line]
|
||||||
|
puts line.gsub(/\s/, ' ')
|
||||||
|
puts ' ' * (err.column-1) + '^'
|
||||||
|
puts ' ' + err.message
|
||||||
|
exit 3
|
||||||
|
end
|
||||||
|
|
||||||
|
if (options.show_ast)
|
||||||
|
require 'pp'
|
||||||
|
pp ast
|
||||||
|
exit 0
|
||||||
|
end
|
||||||
|
|
||||||
|
case options.target
|
||||||
|
when :arm
|
||||||
|
require_relative 'arm_assembler.rb'
|
||||||
|
as_module = Asm::Arm
|
||||||
|
as_target = Elf::Constants::TARGET_ARM
|
||||||
|
when :ttk91
|
||||||
|
require_relative 'ttk91_assembler.rb'
|
||||||
|
as_module = Asm::TTK91
|
||||||
|
as_target = Elf::Constants::TARGET_TTK91
|
||||||
|
end
|
||||||
|
|
||||||
|
asm = Asm::AstAssembler.new(as_module)
|
||||||
|
begin
|
||||||
|
asm.load_ast ast
|
||||||
|
data = StringIO.new
|
||||||
|
asm.assemble(data)
|
||||||
|
symbols = asm.symbols
|
||||||
|
rescue Asm::AssemblyError => err
|
||||||
|
if (err.node)
|
||||||
|
puts 'as: assembly error on line %d, column %d' % [
|
||||||
|
err.node.line+1, err.node.column+1]
|
||||||
|
line = code.split("\n")[err.node.line]
|
||||||
|
puts line.gsub(/\s/, ' ')
|
||||||
|
puts ' ' * (err.node.column-1) + '^'
|
||||||
|
puts ' ' + err.message
|
||||||
|
else
|
||||||
|
puts 'as: ' + err.message
|
||||||
|
end
|
||||||
|
exit 4
|
||||||
|
end
|
||||||
|
|
||||||
|
writer = Asm::ObjectWriter.new(as_target)
|
||||||
|
writer.set_text data.string
|
||||||
|
|
||||||
|
reloc_name_ref = {}
|
||||||
|
|
||||||
|
symbols.each { |symbol|
|
||||||
|
label = symbol[:label]
|
||||||
|
if (label.extern?)
|
||||||
|
reloc_name_ref[label] = symbol[:name]
|
||||||
|
writer.add_reloc_symbol symbol[:name]
|
||||||
|
else
|
||||||
|
writer.add_symbol symbol[:name], symbol[:label].address, symbol[:linkage]
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
asm.relocations.each { |reloc|
|
||||||
|
writer.add_reloc reloc.position, reloc_name_ref[reloc.label], reloc.type
|
||||||
|
}
|
||||||
|
|
||||||
|
begin
|
||||||
|
writer.save(options.output_file)
|
||||||
|
rescue => err
|
||||||
|
puts 'as: cannot save output file: ' + err.message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if (__FILE__ == $0)
|
||||||
|
Asm::CommandLine.new.run
|
||||||
|
end
|
19
unused/elf_object.rb
Normal file
19
unused/elf_object.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
if (__FILE__ == $0)
|
||||||
|
obj = Elf::ObjectFile.new Elf::TARGET_ARM
|
||||||
|
|
||||||
|
sym_strtab = Elf::StringTableSection.new(".strtab")
|
||||||
|
obj.add_section sym_strtab
|
||||||
|
symtab = Elf::SymbolTableSection.new(".symtab", sym_strtab)
|
||||||
|
obj.add_section symtab
|
||||||
|
|
||||||
|
text_section = Elf::TextSection.new(".text")
|
||||||
|
obj.add_section text_section
|
||||||
|
|
||||||
|
symtab.add_func_symbol "_start", 0, text_section, Elf::STB_GLOBAL
|
||||||
|
|
||||||
|
fp = File.open("test.o", "wb")
|
||||||
|
obj.write fp
|
||||||
|
|
||||||
|
fp.close
|
||||||
|
end
|
||||||
|
|
223
unused/parser.rb
Normal file
223
unused/parser.rb
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
require_relative 'str_scanner'
|
||||||
|
require_relative 'nodes'
|
||||||
|
class NumEquivAddrNode < NumLiteralNode
|
||||||
|
end
|
||||||
|
class LabelEquivAddrNode < LabelRefNode
|
||||||
|
end
|
||||||
|
class ToplevelNode < Node
|
||||||
|
attr_accessor :children
|
||||||
|
end
|
||||||
|
class DirectiveNode < Node
|
||||||
|
attr_accessor :name, :value
|
||||||
|
end
|
||||||
|
class LabelNode < Node
|
||||||
|
attr_accessor :name
|
||||||
|
end
|
||||||
|
class MathNode < Node
|
||||||
|
attr_accessor :left, :right, :op
|
||||||
|
alias_method :argument, :left
|
||||||
|
alias_method :argument=, :left=
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
module Asm
|
||||||
|
class Parser
|
||||||
|
def initialize(str)
|
||||||
|
scanner = Asm::Scanner.new(str)
|
||||||
|
|
||||||
|
@ast = parse_toplevel scanner
|
||||||
|
end
|
||||||
|
attr_reader :ast
|
||||||
|
|
||||||
|
def self.parse(str)
|
||||||
|
new(str).ast
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_toplevel(s)
|
||||||
|
node = ToplevelNode.new(s)
|
||||||
|
node.children = []
|
||||||
|
while (not s.eos?)
|
||||||
|
node.children << parse(s)
|
||||||
|
end
|
||||||
|
node
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse(s)
|
||||||
|
s.scan /\s*/
|
||||||
|
node = nil
|
||||||
|
%w(comment directive label instruction).each { |em|
|
||||||
|
if (node = send('parse_'+em, s))
|
||||||
|
break
|
||||||
|
end
|
||||||
|
}
|
||||||
|
raise Asm::ParseError.new('could not parse element', s) unless node
|
||||||
|
s.scan /\s*/
|
||||||
|
node
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_comment(s)
|
||||||
|
if (s.scan(/;.*?$/))
|
||||||
|
CommentNode.new(s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_directive(s)
|
||||||
|
if (m = s.scan(/\.(\w+)(?:(?!$)\s+(.+)\s*?$)?/))
|
||||||
|
DirectiveNode.new(s) { |n|
|
||||||
|
n.name = m[0]
|
||||||
|
n.value = m[1]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_label(s)
|
||||||
|
if (m = s.scan(/(\/*\w+):/))
|
||||||
|
LabelNode.new(s) { |n|
|
||||||
|
n.name = m[0]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_instruction(s)
|
||||||
|
if (m = s.scan(/(\w+)/))
|
||||||
|
node = InstructionNode.new(s) { |n|
|
||||||
|
n.opcode = m[0]
|
||||||
|
n.args = []
|
||||||
|
}
|
||||||
|
if (not s.scan(/\s*($|;)/))
|
||||||
|
loop {
|
||||||
|
arg = parse_arg(s)
|
||||||
|
node.args << arg
|
||||||
|
break if not s.scan(/\s*,/)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
node
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_arg(s)
|
||||||
|
s.scan /\s*/
|
||||||
|
node = nil
|
||||||
|
%w(reference register register_list num_literal label_ref).each { |em|
|
||||||
|
if (node = send('parse_'+em, s))
|
||||||
|
break
|
||||||
|
end
|
||||||
|
}
|
||||||
|
raise Asm::ParseError.new('expected argument but none found', s) unless node
|
||||||
|
|
||||||
|
if (node2 = parse_arg_op(s))
|
||||||
|
node2.argument = node
|
||||||
|
node = node2
|
||||||
|
end
|
||||||
|
|
||||||
|
s.scan /\s*/
|
||||||
|
node
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_arg_op(s)
|
||||||
|
s.scan /\s*/
|
||||||
|
node = nil
|
||||||
|
%w(shift math).each do |em|
|
||||||
|
if (node = send('parse_'+em, s))
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
s.scan /\s*/
|
||||||
|
node
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_shift(s)
|
||||||
|
if (m = s.scan(/(lsl|lsr|asr|ror|rrx)\s+/i))
|
||||||
|
op = m[0].downcase
|
||||||
|
if (op == 'rrx' or arg = parse_arg(s))
|
||||||
|
ShiftNode.new(s) { |n|
|
||||||
|
n.type = m[0].downcase
|
||||||
|
n.value = arg
|
||||||
|
}
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_math(s)
|
||||||
|
if (m = s.scan_str(/[\+\-]/))
|
||||||
|
if (arg1 = parse_arg(s))
|
||||||
|
MathNode.new(s) do |n|
|
||||||
|
n.right = arg1
|
||||||
|
n.op = m
|
||||||
|
end
|
||||||
|
else
|
||||||
|
raise Asm::ParseError.new('expected right side for arithmetic op', s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
REGISTER_REGEXP = Regexp.union(*%w(r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12
|
||||||
|
r13 r14 r15 a1 a2 a3 a4 v1 v2 v3 v4 v5 v6
|
||||||
|
rfp sl fp ip sp lr pc
|
||||||
|
))
|
||||||
|
def parse_register(s)
|
||||||
|
if (m = s.scan_str(REGISTER_REGEXP))
|
||||||
|
RegisterNode.new(s) { |n|
|
||||||
|
n.name = m
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_register_list(s)
|
||||||
|
if (m = s.scan(/\{/))
|
||||||
|
node = RegisterListNode.new(s) do |n|
|
||||||
|
n.registers = []
|
||||||
|
end
|
||||||
|
loop do
|
||||||
|
s.scan /\s*/
|
||||||
|
reg = parse_register(s)
|
||||||
|
if (not reg)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
s.scan /\s*,?/
|
||||||
|
|
||||||
|
node.registers << reg
|
||||||
|
|
||||||
|
if (s.scan(/\}/))
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
node
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_num_literal(s)
|
||||||
|
if (m = s.scan(/(=?)#(-?(?:0x)?[0-9A-Fa-f]+)/))
|
||||||
|
(m[0] == '=' ? NumEquivAddrNode : NumLiteralNode).new(s) { |n|
|
||||||
|
n.value = Integer(m[1])
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_label_ref(s)
|
||||||
|
if (m = s.scan(/(=?)(\/*\w+)/))
|
||||||
|
(m[0] == '=' ? LabelEquivAddrNode : LabelRefNode).new(s) { |n|
|
||||||
|
n.label = m[1]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_reference(s)
|
||||||
|
if (m = s.scan(/\[/))
|
||||||
|
arg = parse_arg(s)
|
||||||
|
if (arg and s.scan(/\]/))
|
||||||
|
ReferenceNode.new(s) do |n|
|
||||||
|
n.argument = arg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if (__FILE__ == $0)
|
||||||
|
p Asm::Parser.parse ARGV[0]
|
||||||
|
end
|
65
unused/str_scanner.rb
Normal file
65
unused/str_scanner.rb
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
module AS; end
|
||||||
|
|
||||||
|
if (not defined? RUBY_ENGINE or not RUBY_ENGINE == 'rbx')
|
||||||
|
class Regexp
|
||||||
|
def match_start(str, idx)
|
||||||
|
Regexp.compile('\A(?:'+source+')').match(str[idx..-1])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Asm::Scanner
|
||||||
|
def initialize(str)
|
||||||
|
@string = str
|
||||||
|
@pos = 0
|
||||||
|
@line = 0
|
||||||
|
@column = 0
|
||||||
|
end
|
||||||
|
attr_accessor :string, :pos, :line, :column, :prev_line, :prev_column
|
||||||
|
|
||||||
|
def rest
|
||||||
|
string[pos..-1]
|
||||||
|
end
|
||||||
|
|
||||||
|
def advance_str(str)
|
||||||
|
self.prev_line = line
|
||||||
|
self.prev_column = column
|
||||||
|
self.pos += str.length
|
||||||
|
self.line += str.count("\n")
|
||||||
|
if (str.include?("\n"))
|
||||||
|
self.column = str.length - str.rindex("\n")
|
||||||
|
else
|
||||||
|
self.column += str.length
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def scan(regexp)
|
||||||
|
if (match = regexp.match_start(rest, 0))
|
||||||
|
advance_str match.to_s
|
||||||
|
match.captures
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def scan_str(regexp)
|
||||||
|
if (match = regexp.match_start(rest, 0))
|
||||||
|
advance_str match.to_s
|
||||||
|
match.to_s
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def lookahead(regexp)
|
||||||
|
if (match = regexp.match_start(rest, 0))
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def eos?
|
||||||
|
pos == string.length
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user