Académique Documents
Professionnel Documents
Culture Documents
linguagem de programação
Dev In Sampa
São Paulo, 28 de novembro de 2009
Por quê?
— Autor desconhecido
— Alan Perlis
Um pouco de conceitos
Linguagem
— Wikipedia
Elementos
PARSING
PEGs
Sem ambigüidades
(Fib of: 2 + 3)
transcribeAndBreak.
AST #2
(Fib of: 2 + 3)
transcribeAndBreak.
Bytecode
push 3
push 2
send +
load Fib
send of:
send transcribeAndBreak
pop
A gramática
Blocos básicos
grammar Mirror
rule statements
(spaces? statement spaces? "." spaces?)* <Statements>
end
rule statement
message_expression
end
rule message_expression
keyword_expression / binary_expression / unary_expression
end
# ...
end
Keywords
grammar Mirror
rule keyword_expression
variable:binary_expression?
keywords:(spaces? keyword spaces expression:binary_expression)+
<KeywordExpression>
end
end
Expressões binárias
grammar Mirror
rule binary_expression
variable:unary_expression spaces?
selector:binary_selector spaces?
expression:binary_expression <BinaryExpression> /
unary_expression
end
# 2 + 3 * (account balance).
# ...
end
Expressões unárias
grammar Mirror
rule unary_expression
variable:primary
selectors:(spaces selector:identifier !colon)+
<UnaryExpression> /
primary
end
end
Juntando as peças
irb> MirrorParser.new.parse('2 + 3.')
module Statements
def build
elements.collect do |element|
Ast::Statement.new(element.statement.build)
end
end
end
class Statement
def initialize(expression)
@expression = expression
end
end
Expressões binárias
# rule binary_expression
# variable:unary_expression spaces?
# selector:binary_selector spaces?
# expression:binary_expression <BinaryExpression> /
# unary_expression
module BinaryExpression
def build
Ast::Message.new(variable.build, selector.text_value, expression.build)
end
end
class Message
def initialize(target, selector, *arguments)
@target = target
@selector = selector
@arguments = arguments
end
end
Juntando as peças
[
#<Ast::Statement
@expression =
#<Ast::Message
@selector = "+",
@target = #<Ast::Literal @value = "2", @type = :integer>,
@arguments = [#<Ast::Literal @value = "3", @type = :integer>]>>
]
Geração de código
Double dispatch
class CodeGenerator
def initialize(ast)
@ast = ast
end
def generate
@ast.collect { |statement| generate_any(statement) }.flatten
end
def generate_any(ast)
send("generate_#{ast.class.name.demodulize.underscore}", ast)
end
# ...
end
Blocos básicos
class CodeGenerator
def generate_statement(ast)
([generate_any(ast.expression)] + [Bytecode::Pop.new]).flatten
end
def generate_variable(ast)
Bytecode::Load.new(ast.name)
end
# ...
end
Mensagens
class CodeGenerator
def generate_message(ast)
instructions = []
ast.arguments.reverse.each do |argument|
instructions += [generate_any(argument)].flatten
end
instructions += [generate_any(ast.target)].flatten
instructions << Bytecode::Message.new(ast.selector)
instructions
end
# ...
end
Bytecodes
class Pop
def inspect
"pop"
end
end
class Message
def initialize(selector)
@selector = selector
@selector_name = get_selector_name(selector)
@selector_method = get_selector_method(selector)
@arity = get_selector_arity(selector)
end
# ...
end
Juntando as peças
irb> CodeGenerator.new(ast).generate
[
push 3,
push 2,
send +,
pop
]
Modelo de execução
Containers & Slots
ACCOUNT
BALANCE 0
USER USER
Universe & World
UNIVERSE WORLD
WORLD MIRRORINTO:
def initialize(instructions)
@instructions = instructions
end
def run
reset_instruction_pointer
while has_instructions?
execute(next_instruction)
end
end
# ...
end
Máquina Virtual
class VM
def execute(instruction)
case instruction
when Bytecode::Implicit
stack_push_and_wrap(current_context)
when Bytecode::Pop
stack.pop
when Bytecode::Push
stack_push_and_wrap(instruction.value)
when Bytecode::Load
stack_push_and_wrap(walk_contexts(instruction.name))
# ...
end
end
end
Juntando as peças
[4]
[4]
Próximos passos
Próximos passos
Arrays
ifTrue:ifFalse et al
to:do et al
Um conjunto de ferramentas
LLVM
Estático ou JIT
module = LLVM::Module.new("mirror")
type = Type::function(MACHINE_WORD, [])
function = module.get_or_insert_function("main", type)
entry_block = function.create_block
exit_block_true = function.create_block
exit_block_false = function.create_block
builder = entry_block.builder
cmp = builder.icmp_sgt(-1.llvm, 1.llvm)
builder.cond_br(cmp, exit_block_true, exit_block_false)
LLVM: Uso
builder = exit_block_true.builder
builder.return(1.llvm)
builder = exit_block_false.builder
builder.return(0.llvm)
ExecutionEngine.get(module)
ExecutionEngine.run_autoconvert(function)
Questões?
@rferraz
http://logbr.reflectivesurface.com