class ZXLib::Basic::Tokenizer

A Basic program tokenizer.

Constants

Token

Attributes

line_index[RW]

Public Class Methods

new(text, line_index=0, line_offset=0) click to toggle source

Creates new instance of a Basic::Tokenizer.

text must be an UTF-8 encoded, line_index and line_offset are for error messages.

# File lib/zxlib/basic.rb, line 702
def initialize(text, line_index=0, line_offset=0)
        @source = text
        @index = line_offset.to_i
        @token = nil
        @line_index = line_index
end

Public Instance Methods

next_token() click to toggle source
# File lib/zxlib/basic.rb, line 723
def next_token
        token = peek_token
        unless token.terminator?
                @token = nil
                token
        end
end
parse_each(&block) click to toggle source
# File lib/zxlib/basic.rb, line 711
def parse_each(&block)
        enu = ::Enumerator.new do |y|
                while token = next_token
                        y << token
                end
        end
        if block_given?
                enu.each(&block)
        else
                enu
        end
end
peek_token() click to toggle source
# File lib/zxlib/basic.rb, line 730
def peek_token
        if @token.nil?
                if @source.empty?
                        @token = Token.new @index, nil, "", nil
                elsif m = Patterns::ESCAPE_MATCH.match(@source)
                        escstr = m.to_s
                        escexpr = m[1]
                        offset = m.end 0
                        @source = m.post_match
                        if m = Patterns::COLOR_CTRL_MATCH_EXACT.match(escexpr)
                                ctrl = CTRL_CODES[m[1]]
                                val = m[2].to_i
                                unless (0..31) === val
                                        raise SyntaxError, "special control arguments must be in a 0..31 range: #{escstr} in line: #{@line_index} at: #{@index}"
                                end
                                chars = [ctrl, val].pack('CC')
                                @token = Token.new @index, chars, chars, nil
                        elsif m = Patterns::CURSOR_CTRL_MATCH_EXACT.match(escexpr)
                                ctrl = CTRL_CODES[m[1]]
                                y, x = m[2].to_i, m[3]
                                if x.nil?
                                        chars = [ctrl, y].pack('Cv')
                                else
                                        chars = [ctrl, y, x.to_i].pack('CCC')
                                end
                                @token = Token.new @index, chars, chars, nil
                        elsif m = Patterns::KEYWORDS_MATCH_EXACT.match(escexpr)
                                code = KEYWORD_CODES[m.to_s]
                                @token = Token.new @index, m.to_s, [code].pack('C'), code
                        else
                                chars = ''
                                code = nil
                                while m = Patterns::ESCAPE_TOKEN_MATCH.match(escexpr)
                                        tok = m[1]
                                        unless code = NON_ASCII_ESCAPE_TOKENS[tok]
                                                code = Integer(tok)
                                                unless (0..255) === code
                                                        raise SyntaxError, "a code must be in a 0..255 range: #{escstr} in line: #{@line_index} at: #{@index}"
                                                end
                                        end
                                        chars << [code].pack('C')
                                        escexpr = m.post_match
                                end
                                unless escexpr.empty? && !chars.empty?
                                        raise SyntaxError, "unknown escape expression: #{escstr} in line: #{@line_index} at: #{@index}"
                                end
                                keyword_code = if chars.bytesize == 1 && (code >= KEYWORD_START_CODE || code < SE_NEW_KEYWORDS_END)
                                        code
                                end
                                @token = Token.new @index, chars, chars, keyword_code
                        end
                        @index += offset
                elsif m = Patterns::BINARY_EXPR_MATCH.match(@source)
                        key = m.to_s
                        @token = Token.new @index, key, key, KEYWORD_CODES['BIN']
                        @index += m.end 0
                        @source = m.post_match
                elsif m = Patterns::KEYWORDS_MATCH.match(@source)
                        key = m.to_s
                        @token = Token.new @index, key, key, KEYWORD_CODES[key.strip]
                        @index += m.end 0
                        @source = m.post_match
                elsif m = Patterns::NUMBER_MATCH.match(@source)
                        @token = Token.new @index, m.to_s, m.to_s, nil
                        @index += m.end 0
                        @source = m.post_match
                else
                        src = @source.slice!(0)
                        code = CHAR_CODES[src]
                        if code.nil?
                                raise SyntaxError, "not sure what to do with the character: \\u#{src.ord.to_s(16).rjust(4,?0)} in line: #{@line_index} at: #{@index}"
                        end
                        @token = Token.new @index, src, [code].pack('C'), nil
                        @index += 1
                end
        end
        @token
end
terminated?() click to toggle source
# File lib/zxlib/basic.rb, line 708
def terminated?
        peek_token.terminator?
end