Programming is hard. Making compilers is harder. Or so people think. The truth is that making a compiler is just a series of small steps, using regular language constructs. It's so easy, we'll make one in this talk.
ImplementingLanguages
View Slide
Thanks FluentConf
Thanks SilverStripe
I Am Not ASpecial Snowflake
Compilers AreNot Important
Great BooksOn The Subject
Why Is This Useful?
Why Is This Useful?▸ Improving productivity▸ Communicating in a common domain language▸ Alternative computational models
Tools You Can Use
Tools You Can Use▸ Compiler generators▸ String manipulation and state machines
int minutes = 90;
Grammar
Grammar▸ List of rules which define structure and syntax▸ Each rule is called a lexeme
int minutes = 90;e ! type id = value | type id
Lexer
Lexer▸ Breaks code string into tokens▸ Lexer ignores nesting
e ! type id = value | type id["type", "int"],["id", "minutes"],["assign", "="],["value", "90"],
Parser
Parser▸ Arranges tokens in a hierarchy▸ Checks tokens for syntax errors
["type", "int"],["id", "minutes"],["assign", "="],["value", "90"],["definition", ["int","minutes","90",]]
Abstract Syntax Tree
Abstract Syntax Tree▸ Represents constructs in the compiler's language
["definition", ["int","minutes","90",]]new Definition("int","minutes","90",)
Interpreter
Interpreter▸ Calculates immediate effect to context▸ Always accepts and returns a context
new Definition("int","minutes","90",)let context = {};for (let i = 0; i < objects.length; i++) {context = objects[i].applyTo(context);}
Compiler
Compiler▸ Writes the AST to a new language▸ Checks constructs for semantic errors in target language
Recap
Yay!
Parser ExpressionGrammar
Parser Expression Grammar▸ Uses pattern matching to tokenise and organise lexemes▸ Generates a reusable interpreter and/or compiler
{var context = {};function __set(key, value) {context[key] = value;}function __get(key) {return context[key];}}
start =expression*expression =_ definition _/_ inspection __ "whitespace" =[ \t\r\n]*
definition "definition" =t:type _ i:id _ assign _ v:value _ terminal {__set(i, v);}/t:type _ i:id _ terminal {__set(i, null);}
type "type" ="int"id "identity" =letters:[a-z]+ {return letters.join("");}assign "assign" ="="value "value" =numbers:[0-9]+ {return parseInt(numbers.join(""), 10);}terminal "terminal" =";"
inspection "inspection" ="inspect" _ i:id _ terminal {console.log(__get(i));}
ThanksCONFERENCES.OREILLY.COM/FLUENT/JAVASCRIPT-HTML-US/PUBLIC/SCHEDULE/DETAIL/46342@ASSERTCHRIS