criando sua própria linguagem de programação
DESCRIPTION
Uma rápida aventura pelo processo de criar uma pequena linguagem de programação para demonstrar Treetop e interpretação de código.TRANSCRIPT
![Page 1: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/1.jpg)
Criando sua própria linguagem de programaçãoDev In SampaSão Paulo, 28 de novembro de 2009
![Page 2: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/2.jpg)
Por quê?
Cada nova linguagem é um campo aberto para livre experimentação
Compilação é uma arena em que todas as suas habilidades são necessárias
![Page 3: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/3.jpg)
A verdade verdadeira
“Por que escrever um programa se você pode escrever um programa para escrever um programa?”
— Autor desconhecido
A verdade verdadeira é que é divertido ;)
![Page 4: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/4.jpg)
Na prática
Você pode usar um parser mais sofisticado para suas DSLs
Você pode resolver problemas de portar código de um domínio para outro com um tradutor
Você pode usar um interpretador para construir geradores mais sofisticados
![Page 5: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/5.jpg)
Na pior das hipóteses...
“Se uma linguagem não é capaz de afetar o modo como você pensa sobre programação, não vale a pena aprendê-la”
— Alan Perlis
![Page 6: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/6.jpg)
Um pouco de conceitos
![Page 7: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/7.jpg)
Linguagem
“Uma notação para escrever programas, que são especificações para a computação de uma algoritmo”
— Wikipedia
![Page 8: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/8.jpg)
Elementos
Sintaxe: o que é escrito, descrita em uma gramática formal
Semântica: o que isso significa, especificado em termos de formalizações de compilação e execução
![Page 9: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/9.jpg)
Gramáticas formais
Value ← [0-9]+ / '(' Expr ')'Product ← Value (('*' / '/') Value)*Sum ← Product (('+' / '-') Product)*Expr ← Sum
![Page 10: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/10.jpg)
Do texto à execuçãoSAÍDA
ANÁLISE SINTÁTICA
ANÁLISE LÉXICA
TOKENS
AST
COMPILADORINTERPRETADOR
TRADUTOR
CÓDIGO FONTE
PARSING
![Page 11: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/11.jpg)
Introduzindo “Mirror”
![Page 12: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/12.jpg)
Inspiração
Sintaxe baseada em Smalltalk e IO
Slot-based como Self
Forte e dinamicamente tipada
Interpretada, via bytecodes
![Page 13: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/13.jpg)
Mirror
World mirrorInto: "Fib".
Fib set: "of:" to: [ n | n <= 2 ifTrue: [ 1. ] ifFalse: [ (of: n - 1) + (of: n - 2). ].].
(Fib of: 10) transcribeAndBreak.
![Page 14: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/14.jpg)
Análise
Via Treetop, um packrat parser em Ruby
PEGs
Análise versus geração
Sem ambigüidades
Gera uma árvore sintática que é compilada para uma representação em bytecodes
![Page 15: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/15.jpg)
AST #1
(Fib of: 2 + 3)transcribeAndBreak.
![Page 16: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/16.jpg)
AST #2
(Fib of: 2 + 3)transcribeAndBreak.
![Page 17: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/17.jpg)
Bytecode
push 3push 2send +load Fibsend of:send transcribeAndBreakpop
![Page 18: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/18.jpg)
A gramática
![Page 19: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/19.jpg)
Blocos básicosgrammar 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
![Page 20: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/20.jpg)
Keywords
grammar Mirror
rule keyword_expression variable:binary_expression? keywords:(spaces? keyword spaces expression:binary_expression)+ <KeywordExpression> end
# Account deposit: 100 from: user. # ...
end
![Page 21: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/21.jpg)
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
![Page 22: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/22.jpg)
Expressões unárias
grammar Mirror
rule unary_expression variable:primary selectors:(spaces selector:identifier !colon)+ <UnaryExpression> / primary end
# (Account current balance) transcribeAndBreak. # ...
end
![Page 23: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/23.jpg)
Juntando as peças
irb> MirrorParser.new.parse('2 + 3.')
SyntaxNode+Statements offset=0, "2 + 3." (build): SyntaxNode+Statements0 offset=0, "2 + 3." (statement): SyntaxNode+BinaryExpression0+BinaryExpression offset=0, "2 + 3": SyntaxNode+IntegerLiteral offset=0, "2" (build): SyntaxNode offset=0, "2" SyntaxNode+Spaces2 offset=1, " ": SyntaxNode offset=2, "+": SyntaxNode offset=2, "+" SyntaxNode+IntegerLiteral offset=4, "3" (build): SyntaxNode offset=4, "3"
![Page 24: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/24.jpg)
Convertendo a AST
![Page 25: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/25.jpg)
Blocos básicos# rule statements# (spaces? statement spaces? "." spaces?)* <Statements># end
module Statements def build elements.collect do |element| Ast::Statement.new(element.statement.build) end endend
class Statement def initialize(expression) @expression = expression endend
![Page 26: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/26.jpg)
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) endend
class Message def initialize(target, selector, *arguments) @target = target @selector = selector @arguments = arguments endend
![Page 27: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/27.jpg)
Juntando as peças
irb> MirrorParser.new.parse('2 + 3.').build
[ #<Ast::Statement @expression = #<Ast::Message @selector = "+", @target = #<Ast::Literal @value = "2", @type = :integer>, @arguments = [#<Ast::Literal @value = "3", @type = :integer>]>>]
![Page 28: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/28.jpg)
Geração de código
![Page 29: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/29.jpg)
Double dispatchclass 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
![Page 30: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/30.jpg)
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
![Page 31: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/31.jpg)
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
![Page 32: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/32.jpg)
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
![Page 33: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/33.jpg)
Juntando as peças
irb> ast = MirrorParser.new.parse('2 + 3.').build
irb> CodeGenerator.new(ast).generate
[ push 3, push 2, send +, pop]
![Page 34: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/34.jpg)
Modelo de execução
![Page 35: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/35.jpg)
Containers & Slots
0
BLOCK CONTEXT
BLOCK CONTEXT
ACCOUNT
DEPOSIT:
BALANCE
WITHDRAW:
USER USER
![Page 36: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/36.jpg)
Universe & WorldUNIVERSE
ERROR
WORLD
WORLD
SET: TO:
MIRRORINTO:
![Page 37: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/37.jpg)
Detalhes
O envio de mensagens acontece em um contexto que é gerado para cada mensagem
Blocos geram contextos empilhados
O interpretador percorre os contextos até encontrar o objeto apropriado para enviar a mensagem
![Page 38: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/38.jpg)
Máquina virtual
![Page 39: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/39.jpg)
Máquina Virtualclass VM def initialize(instructions) @instructions = instructions end
def run reset_instruction_pointer while has_instructions? execute(next_instruction) end end # ...
end
![Page 40: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/40.jpg)
Máquina Virtualclass 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
![Page 41: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/41.jpg)
Juntando as peças
irb> Interpreter.run(true, "World offload: 2 + 2.")
[4]
irb> Interpreter.run(true, "World offload: [ 2 + 2. ] value.")
[4]
![Page 42: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/42.jpg)
Próximos passos
![Page 43: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/43.jpg)
Próximos passos
Arrays
Inlining de mensagens comuns
Primitivas: + - * / at: at:put:
ifTrue:ifFalse et al
to:do et al
Melhor uso de blocos
![Page 44: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/44.jpg)
LLVM
Uma estratégia de compilação
Um conjunto de instruções virtualizado
Uma infra-estrutura de compilação
Um conjunto de ferramentas
![Page 45: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/45.jpg)
LLVM
Efetivamente uma DSL para geração de código intermediário otimizado e portável
Estático ou JIT
Usado por MacRuby, Rubinius, Unladden Swallow e outros
![Page 46: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/46.jpg)
LLVM: Uso
Transformar slots de código em funções
Transformar closures em funções quando não fizer sentido que os mesmos sejam inline
Compilar o próprio interpretador para ser parcialmente jitted
![Page 47: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/47.jpg)
LLVM: Uso
module = LLVM::Module.new("mirror")type = Type::function(MACHINE_WORD, [])function = module.get_or_insert_function("main", type)
entry_block = function.create_blockexit_block_true = function.create_blockexit_block_false = function.create_block
builder = entry_block.buildercmp = builder.icmp_sgt(-1.llvm, 1.llvm)builder.cond_br(cmp, exit_block_true, exit_block_false)
![Page 48: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/48.jpg)
LLVM: Uso
builder = exit_block_true.builderbuilder.return(1.llvm)
builder = exit_block_false.builderbuilder.return(0.llvm)
ExecutionEngine.get(module)ExecutionEngine.run_autoconvert(function)
![Page 49: Criando sua própria linguagem de programação](https://reader033.vdocuments.pub/reader033/viewer/2022061521/55731d00d8b42aae7b8b49a3/html5/thumbnails/49.jpg)
Questões?
@rferrazhttp://logbr.reflectivesurface.com