Criando sua própria linguagem de programação
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Criando sua própria linguagem de programação

on

  • 13,738 views

Uma rápida aventura pelo processo de criar uma pequena linguagem de programação para demonstrar Treetop e interpretação de código.

Uma rápida aventura pelo processo de criar uma pequena linguagem de programação para demonstrar Treetop e interpretação de código.

Statistics

Views

Total Views
13,738
Views on SlideShare
13,263
Embed Views
475

Actions

Likes
5
Downloads
153
Comments
0

5 Embeds 475

http://logbr.reflectivesurface.com 461
http://www.slideshare.net 7
http://www.mefeedia.com 3
http://feeds.feedburner.com 3
http://www.google.com.br 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

CC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Criando sua própria linguagem de programação Presentation Transcript

  • 1. Criando sua própria linguagem de programação Dev In Sampa São Paulo, 28 de novembro de 2009
  • 2. 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
  • 3. 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 ;)
  • 4. 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
  • 5. 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
  • 6. Um pouco de conceitos
  • 7. Linguagem “Uma notação para escrever programas, que são especificações para a computação de uma algoritmo” — Wikipedia
  • 8. 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
  • 9. Gramáticas formais Value ← [0-9]+ / '(' Expr ')' Product ← Value (('*' / '/') Value)* Sum ← Product (('+' / '-') Product)* Expr ← Sum
  • 10. Do texto à execução CÓDIGO FONTE SAÍDA PARSING ANÁLISE LÉXICA COMPILADOR INTERPRETADOR TRADUTOR TOKENS ANÁLISE SINTÁTICA AST
  • 11. Introduzindo “Mirror”
  • 12. Inspiração Sintaxe baseada em Smalltalk e IO Slot-based como Self Forte e dinamicamente tipada Interpretada, via bytecodes
  • 13. Mirror World mirrorInto: "Fib". Fib set: "of:" to: [ n | n <= 2 ifTrue: [ 1. ] ifFalse: [ (of: n - 1) + (of: n - 2). ]. ]. (Fib of: 10) transcribeAndBreak.
  • 14. 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
  • 15. AST #1 (Fib of: 2 + 3) transcribeAndBreak.
  • 16. AST #2 (Fib of: 2 + 3) transcribeAndBreak.
  • 17. Bytecode push 3 push 2 send + load Fib send of: send transcribeAndBreak pop
  • 18. A gramática
  • 19. 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
  • 20. Keywords grammar Mirror rule keyword_expression variable:binary_expression? keywords:(spaces? keyword spaces expression:binary_expression)+ <KeywordExpression> end # Account deposit: 100 from: user. # ... end
  • 21. 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
  • 22. Expressões unárias grammar Mirror rule unary_expression variable:primary selectors:(spaces selector:identifier !colon)+ <UnaryExpression> / primary end # (Account current balance) transcribeAndBreak. # ... end
  • 23. 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"
  • 24. Convertendo a AST
  • 25. 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 end end class Statement def initialize(expression) @expression = expression end end
  • 26. 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
  • 27. 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>]>> ]
  • 28. Geração de código
  • 29. 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
  • 30. 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
  • 31. 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
  • 32. 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
  • 33. Juntando as peças irb> ast = MirrorParser.new.parse('2 + 3.').build irb> CodeGenerator.new(ast).generate [ push 3, push 2, send +, pop ]
  • 34. Modelo de execução
  • 35. Containers & Slots ACCOUNT BALANCE 0 DEPOSIT: BLOCK CONTEXT WITHDRAW: BLOCK CONTEXT USER USER
  • 36. Universe & World UNIVERSE WORLD WORLD MIRRORINTO: ERROR SET: TO:
  • 37. 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
  • 38. Máquina virtual
  • 39. Máquina Virtual class VM def initialize(instructions) @instructions = instructions end def run reset_instruction_pointer while has_instructions? execute(next_instruction) end end # ... end
  • 40. 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
  • 41. Juntando as peças irb> Interpreter.run(true, "World offload: 2 + 2.") [4] irb> Interpreter.run(true, "World offload: [ 2 + 2. ] value.") [4]
  • 42. Próximos passos
  • 43. Próximos passos Arrays Inlining de mensagens comuns Primitivas: + - * / at: at:put: ifTrue:ifFalse et al to:do et al Melhor uso de blocos
  • 44. LLVM Uma estratégia de compilação Um conjunto de instruções virtualizado Uma infra-estrutura de compilação Um conjunto de ferramentas
  • 45. 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
  • 46. 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
  • 47. LLVM: Uso 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)
  • 48. 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)
  • 49. Questões? @rferraz http://logbr.reflectivesurface.com