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