first commit
commit
609dbf39d2
@ -0,0 +1,35 @@
|
|||||||
|
class PrintyBoy
|
||||||
|
def initialize(stream)
|
||||||
|
@stream = stream
|
||||||
|
end
|
||||||
|
|
||||||
|
def print_em
|
||||||
|
@stream.each {|y| puts y}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class CharStream
|
||||||
|
include Enumerable
|
||||||
|
|
||||||
|
def initialize(str)
|
||||||
|
puts "str.chars: #{str.chars.class} of #{str.chars.length} chars"
|
||||||
|
@str = str.chars
|
||||||
|
end
|
||||||
|
|
||||||
|
def each(&block)
|
||||||
|
@str.each &block
|
||||||
|
end
|
||||||
|
|
||||||
|
def empty?
|
||||||
|
@str.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def length
|
||||||
|
@str.length
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
cs = CharStream.new "cockshitbitchcuntaahhhh"
|
||||||
|
pb = PrintyBoy.new cs
|
||||||
|
|
||||||
|
pb.print_em
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
@interface NSRuby : NSObject {
|
||||||
|
int x, y;
|
||||||
|
}
|
||||||
|
-(void) sayHello;
|
||||||
|
+(NSString *) scientificName;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation
|
||||||
|
-(void) sayHello {
|
||||||
|
NSLog(@"Hello, World!");
|
||||||
|
}
|
||||||
|
|
||||||
|
+(NSString *) scientificName {
|
||||||
|
int x = 2 + 5 * 5 / 8;
|
||||||
|
return @"Homo Sapien!";
|
||||||
|
}
|
||||||
|
@end
|
||||||
@ -0,0 +1,329 @@
|
|||||||
|
#!/usr/bin/ruby
|
||||||
|
|
||||||
|
def error(msg)
|
||||||
|
puts "ERROR: #{msg}"
|
||||||
|
exit 0
|
||||||
|
end
|
||||||
|
|
||||||
|
TokenTypes = {
|
||||||
|
:blackspace => /\S+/,
|
||||||
|
:whitespace => /\s+/
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicTokens = {
|
||||||
|
:open_brace => /{/,
|
||||||
|
:closed_brace => /}/,
|
||||||
|
:open_paren => /\(/,
|
||||||
|
:closed_paren => /\)/,
|
||||||
|
:open_bracket => /\[/,
|
||||||
|
:closed_bracket => /\]/,
|
||||||
|
:comma => /,/,
|
||||||
|
:dot => /\./,
|
||||||
|
:double_quote => /\"/,
|
||||||
|
:single_quote => /\'/,
|
||||||
|
:plus => /\+/,
|
||||||
|
:minus => /\-/,
|
||||||
|
:mult => /\*/,
|
||||||
|
:div => /\//,
|
||||||
|
:number => /[0-9]+/,
|
||||||
|
:colon => /:/,
|
||||||
|
:semicolon => /;/,
|
||||||
|
|
||||||
|
:text => /\S/,
|
||||||
|
:whitespace => /\s+/,
|
||||||
|
:doubleq => /\"/,
|
||||||
|
}
|
||||||
|
|
||||||
|
KeywordTokens = {
|
||||||
|
:intf_decl => /@interface/,
|
||||||
|
:impl_decl => /@implementation/,
|
||||||
|
:end => /@end/,
|
||||||
|
:property => /@property/,
|
||||||
|
:synthezize => /@synthesize/,
|
||||||
|
}
|
||||||
|
|
||||||
|
class Token
|
||||||
|
attr_reader :str
|
||||||
|
attr_accessor :type
|
||||||
|
attr_accessor :matcher
|
||||||
|
|
||||||
|
def initialize(str, hash)
|
||||||
|
@matcher = Matcher.new(hash)
|
||||||
|
@str, @type = str, @matcher.match(str)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"#{@type}: #{@str}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def combine(token)
|
||||||
|
@str << token.str
|
||||||
|
end
|
||||||
|
|
||||||
|
def match_with(hash)
|
||||||
|
return self unless Token.new(str, hash).matcher.match(@str)
|
||||||
|
Token.new(str, hash)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Matcher
|
||||||
|
def initialize(hash)
|
||||||
|
@hash = hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def match(val)
|
||||||
|
@hash.each {|k,v|
|
||||||
|
return k if val =~ v
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ModeMatcher
|
||||||
|
def initialize(hash)
|
||||||
|
@hash = hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def match(val)
|
||||||
|
@hash.each {|k,v|
|
||||||
|
return k if val == v
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Modes = {
|
||||||
|
:intf_decl => :intf_decl,
|
||||||
|
:impl_decl => :impl_decl,
|
||||||
|
:end => :end,
|
||||||
|
}
|
||||||
|
|
||||||
|
class VarDecl
|
||||||
|
def initialize(type, name)
|
||||||
|
@type = type
|
||||||
|
@name = name
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"#{@type} #{@name};"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class VariableDecl
|
||||||
|
def initialize(stream)
|
||||||
|
@stream = stream
|
||||||
|
@modes = [:type, :var, :semicolon]
|
||||||
|
@mode = :type
|
||||||
|
end
|
||||||
|
|
||||||
|
def new_from(type, vars)
|
||||||
|
vars.map { |v|
|
||||||
|
VarDecl.new(type, v)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse
|
||||||
|
vars = []
|
||||||
|
|
||||||
|
until @stream.empty?
|
||||||
|
token = @stream.shift
|
||||||
|
@mode = token.type if token.type == :semicolon
|
||||||
|
|
||||||
|
case @mode
|
||||||
|
when :type
|
||||||
|
type = token
|
||||||
|
@mode = var
|
||||||
|
when :var
|
||||||
|
vars << token
|
||||||
|
when :semicolon
|
||||||
|
return [VariableDecl.new_from(type, vars), @stream]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class InterfaceDeclHeader
|
||||||
|
def initialize(name, superclass)
|
||||||
|
@name, @superclass = name, superclass
|
||||||
|
@type = :intf_decl_header
|
||||||
|
@expect = [:intf_struct_member, :intf_property, :intf_method]
|
||||||
|
@microexpect = {
|
||||||
|
:open_brace => :intf_struct_member,
|
||||||
|
:kw_property => :intf_property,
|
||||||
|
:minus => :intf_method,
|
||||||
|
:plus => :class_method,
|
||||||
|
:end => :any,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.new_from(par)
|
||||||
|
first = par.shift
|
||||||
|
name = par.shift
|
||||||
|
par.shift
|
||||||
|
superclass = par.shift
|
||||||
|
InterfaceDeclHeader.new(name, superclass)
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse(stream)
|
||||||
|
token = stream.shift
|
||||||
|
expected = @microexpect[token]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class InterfaceStructMember
|
||||||
|
def initialize(type, name)
|
||||||
|
@vartype, @name = vartype, name
|
||||||
|
@type = :intf_struct_member
|
||||||
|
@expect = [:intf_struct_member, :intf_property, :intf_method]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class InterfaceMethod
|
||||||
|
def initialize(return_type, name, args)
|
||||||
|
@return_type, @name, @args = return_type, name, args
|
||||||
|
@type = :intf_method
|
||||||
|
@expect [:intf_method, :end]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class InterfaceDecl
|
||||||
|
def initialize(name, superclass)
|
||||||
|
@name, @superclass = name, superclass
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.new_from(args)
|
||||||
|
first = args.shift
|
||||||
|
puts first if first != "@interface"
|
||||||
|
name = args.shift
|
||||||
|
args.shift
|
||||||
|
superclass = args.shift
|
||||||
|
InterfaceDecl.new(name, superclass)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"@interface #{@name.str} : #{@superclass.str}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ModeSwitch
|
||||||
|
def initialize(state)
|
||||||
|
@state = state
|
||||||
|
end
|
||||||
|
|
||||||
|
def switch(mode)
|
||||||
|
@state.mode = mode if @state.modes.include? mode
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class SyntaxTape
|
||||||
|
attr_accessor :processed
|
||||||
|
attr_accessor :remainder
|
||||||
|
def initialize(processed, remainder)
|
||||||
|
@processed, @remainder = processed, remainder
|
||||||
|
end
|
||||||
|
|
||||||
|
def process(parser)
|
||||||
|
#this should return yet another syntaxtape
|
||||||
|
parser.parse(@remainder)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class StateMachineA
|
||||||
|
attr_accessor :mode
|
||||||
|
attr_reader :modes
|
||||||
|
|
||||||
|
def initialize(stream)
|
||||||
|
@stream = stream
|
||||||
|
@modes = [:intf_decl, :impl_decl, :end]
|
||||||
|
@mode = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse
|
||||||
|
matcher = ModeSwitch.new(self)
|
||||||
|
parameters = []
|
||||||
|
class_type = nil
|
||||||
|
until @stream.empty?
|
||||||
|
token = @stream.shift
|
||||||
|
matcher.switch(token.type)
|
||||||
|
|
||||||
|
case @mode
|
||||||
|
when :intf_decl
|
||||||
|
class_type = InterfaceDeclHeader
|
||||||
|
parameters << token unless token.type == :whitespace
|
||||||
|
when :impl_decl
|
||||||
|
class_type = ImplDeclHeader
|
||||||
|
parameters << token unless token.type == :whitespace
|
||||||
|
when :end
|
||||||
|
parameters << token
|
||||||
|
return SyntaxTape.new(class_type.new_from(parameters), @stream)
|
||||||
|
else
|
||||||
|
puts "unknown state: #{@mode}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Lexer
|
||||||
|
include Enumerable
|
||||||
|
|
||||||
|
def keywords
|
||||||
|
[/@interface/]
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(file)
|
||||||
|
error("expected input file") if file.nil?
|
||||||
|
@source = File.read(file)
|
||||||
|
end
|
||||||
|
|
||||||
|
def each(&block)
|
||||||
|
@source.each_char(&block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def blackmap
|
||||||
|
self.map {|c|
|
||||||
|
Token.new(c, c=~/\s/ ? :whitespace : :blackspace)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def matchmap
|
||||||
|
tokens = self.map {|c|
|
||||||
|
Token.new(c, BasicTokens)
|
||||||
|
}
|
||||||
|
|
||||||
|
bleed = 0
|
||||||
|
|
||||||
|
tokens.filter_map.with_index {|token, idx|
|
||||||
|
#skips iterations that would result in repeated segments of string
|
||||||
|
if bleed != 0
|
||||||
|
bleed -= 1
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
next token unless token.type == :text
|
||||||
|
#combine text into single token
|
||||||
|
while tokens[idx += 1].type == :text
|
||||||
|
token.combine(tokens[idx])
|
||||||
|
bleed += 1
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
next token
|
||||||
|
}.map { |token|
|
||||||
|
token.match_with(KeywordTokens)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def each_token
|
||||||
|
token = ""
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
source = Lexer.new(ARGV[0])
|
||||||
|
a = StateMachineA.new source.matchmap
|
||||||
|
tape = a.parse
|
||||||
|
puts tape.processed
|
||||||
@ -0,0 +1,125 @@
|
|||||||
|
intf_decl: @interface
|
||||||
|
whitespace:
|
||||||
|
text: NSRuby
|
||||||
|
whitespace:
|
||||||
|
colon: :
|
||||||
|
whitespace:
|
||||||
|
text: NSObject
|
||||||
|
whitespace:
|
||||||
|
open_brace: {
|
||||||
|
whitespace:
|
||||||
|
whitespace:
|
||||||
|
whitespace:
|
||||||
|
whitespace:
|
||||||
|
text: int
|
||||||
|
whitespace:
|
||||||
|
text: x
|
||||||
|
comma: ,
|
||||||
|
whitespace:
|
||||||
|
text: y
|
||||||
|
semicolon: ;
|
||||||
|
whitespace:
|
||||||
|
closed_brace: }
|
||||||
|
whitespace:
|
||||||
|
minus: -
|
||||||
|
open_paren: (
|
||||||
|
text: void
|
||||||
|
closed_paren: )
|
||||||
|
whitespace:
|
||||||
|
text: sayHello
|
||||||
|
semicolon: ;
|
||||||
|
whitespace:
|
||||||
|
plus: +
|
||||||
|
open_paren: (
|
||||||
|
text: NSString
|
||||||
|
whitespace:
|
||||||
|
mult: *
|
||||||
|
closed_paren: )
|
||||||
|
whitespace:
|
||||||
|
text: scientificName
|
||||||
|
semicolon: ;
|
||||||
|
whitespace:
|
||||||
|
end: @end
|
||||||
|
whitespace:
|
||||||
|
whitespace:
|
||||||
|
impl_decl: @implementation
|
||||||
|
whitespace:
|
||||||
|
minus: -
|
||||||
|
open_paren: (
|
||||||
|
text: void
|
||||||
|
closed_paren: )
|
||||||
|
whitespace:
|
||||||
|
text: sayHello
|
||||||
|
whitespace:
|
||||||
|
open_brace: {
|
||||||
|
whitespace:
|
||||||
|
whitespace:
|
||||||
|
whitespace:
|
||||||
|
whitespace:
|
||||||
|
text: NSLog
|
||||||
|
open_paren: (
|
||||||
|
text: @
|
||||||
|
double_quote: "
|
||||||
|
text: Hello
|
||||||
|
comma: ,
|
||||||
|
whitespace:
|
||||||
|
text: World!
|
||||||
|
double_quote: "
|
||||||
|
closed_paren: )
|
||||||
|
semicolon: ;
|
||||||
|
whitespace:
|
||||||
|
closed_brace: }
|
||||||
|
whitespace:
|
||||||
|
whitespace:
|
||||||
|
plus: +
|
||||||
|
open_paren: (
|
||||||
|
text: NSString
|
||||||
|
whitespace:
|
||||||
|
mult: *
|
||||||
|
closed_paren: )
|
||||||
|
whitespace:
|
||||||
|
text: scientificName
|
||||||
|
whitespace:
|
||||||
|
open_brace: {
|
||||||
|
whitespace:
|
||||||
|
whitespace:
|
||||||
|
whitespace:
|
||||||
|
whitespace:
|
||||||
|
text: int
|
||||||
|
whitespace:
|
||||||
|
text: x
|
||||||
|
whitespace:
|
||||||
|
text: =
|
||||||
|
whitespace:
|
||||||
|
number: 2
|
||||||
|
whitespace:
|
||||||
|
plus: +
|
||||||
|
whitespace:
|
||||||
|
number: 5
|
||||||
|
whitespace:
|
||||||
|
mult: *
|
||||||
|
whitespace:
|
||||||
|
number: 5
|
||||||
|
whitespace:
|
||||||
|
div: /
|
||||||
|
whitespace:
|
||||||
|
number: 8
|
||||||
|
semicolon: ;
|
||||||
|
whitespace:
|
||||||
|
whitespace:
|
||||||
|
whitespace:
|
||||||
|
whitespace:
|
||||||
|
text: return
|
||||||
|
whitespace:
|
||||||
|
text: @
|
||||||
|
double_quote: "
|
||||||
|
text: Homo
|
||||||
|
whitespace:
|
||||||
|
text: Sapien!
|
||||||
|
double_quote: "
|
||||||
|
semicolon: ;
|
||||||
|
whitespace:
|
||||||
|
closed_brace: }
|
||||||
|
whitespace:
|
||||||
|
end: @end
|
||||||
|
whitespace:
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
class Parser
|
||||||
|
def initialize(pattern)
|
||||||
|
@pattern = pattern
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse(stream)
|
||||||
|
a = stream.chars
|
||||||
|
b = a.shift
|
||||||
|
if b =~ @pattern
|
||||||
|
return [b, parse(a.join)]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
parser = ->(str) {
|
||||||
|
parser.call [str[1].flatten.chars.first, str[1].flatten.chars.drop(1)]
|
||||||
|
}
|
||||||
|
|
||||||
|
p parser.call ["", "Hello, World"]
|
||||||
Loading…
Reference in New Issue