Skip to content

Instantly share code, notes, and snippets.

@mgechev
Last active February 19, 2016 10:02
Show Gist options
  • Save mgechev/9a2e7fa50435fcbd40bb to your computer and use it in GitHub Desktop.
Save mgechev/9a2e7fa50435fcbd40bb to your computer and use it in GitHub Desktop.

Grammar

EBNF

program = statement+
statement = expression | if_statement
if_statement = 'if' '(' expression ')' { statement+ }
expression = number (+ expression)*

Program based on our grammar

if (1) {
  if (0) {
    42 + 12 + 2
  }
  2 + 3
}
2 + 1

Lexer/Tokenizer/Scanner

[
  {
    lexeme: 'if',
    type: 'keyword',
    position: {
      line: 0,
      char: 0
    }
  },
  {
    lexeme: '(',
    type: 'open_bracket'
    position: {
      line: 0,
      char: 3
    }
  },
  {
    lexeme: 1,
    type: 'number',
    position: {
      line: 0,
      char: 4
    }
  },
  {
    lexeme: ')',
    type: 'close_bracket',
    position: {
      line: 0,
      char: 5
    }
  },
  ...
]

Parsing

Recursive-Decent Parser

AST (Abstract-Syntax Tree)

      PROGRAM
     /       \
    if       ...
   / \
cond  body
 |   /    \
 1  if    ...
   /  \
 cond body
  |    |  \
  0    +
      / \
     42  +
        / \
       12  2

Interpretation

Visitor Pattern

class InterpretationVisitor {
  execute(ast) {
    ast.statements.forEach(this.visitNode.bind(this));
  }
  visitNode(node) {
    switch (node.type) {
      case 'if_statement':
      return this.visitIfStatement(node);
      break;
      case 'expression':
      return this.visitExpression(node);
      break;
      default:
      throw new Error('Unrecognized node');
    }
  }
  visitIfStatement(node) {
    if (this.visitNode(node.condition)) {
      node.statements.forEach(this.visitNode.bind(this));
    }
  }
  visitExpression(node) {
    if (node.operator) {
      return this.visitNode(node.left) + this.visitNode(node.right);
    }
    return node.value;
  }
}

TypeScript Specific

@Directive({
  selector: '[foo-bar]'
})
class Foo {...}

TypeScript Visitor

class DirectiveVisitor {
  // ...
  visitClassDeclaration(node) {
    (node.decorator || []).forEach(this.visitDecorator.bind(this));
  }
  visitDecorator(decorator) {
    //...
  }
  // ...
}

Links

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment