UP | HOME

Compilers Overview
Lecture 2

Table of Contents

Review

  • What is a compiler?
  • Compilers vs. interpreters
  • Symbols vs. meaning

Questions about the last class?

  • Dragon book pg55 (2.3.2) pg69 (2.5)

How would you describe C?

  • Someone asks you to explain how the C language works
  • How would you do it?
  • What do arithmetic operations do?
  • What does x=2+1; x=x+1 mean?
    • Contradicts traditional math equality
  • What do loops do?

Translating to postfix

  • Input: three times two plus one
  • Output: 3 2 * 1 +

Defining the syntax

expression -> expression operator number
expression -> number
number -> one
number -> two
...
number -> nine
operator -> plus
operator -> times
expression -> expression operator number
  { expression0.value = concat(expression1.value, number.value, operator.value) }
expression -> number  { expression.value = number.value }
number -> one     { number.value = "1" }
number -> two     { number.value = "2" }
...
number -> nine    { number.value = "9" }
operator -> plus  { operator.value = "+" }
operator -> times { operator.value = "*" }

Defining the translation over the syntax

  • Start with syntax
  • Define semantic rules (Dragon Book 2.3.2)
    • "Code" executed after each syntactic rule is matched
    • Store "return values" for parent syntax to use
  • Examples
    • number -> nine { print "9" }
    • operator -> plus { operator.value = "+" }
expression -> expression operator number     { expression.value = concat(expression.value, number.value, operator.value) }
expression -> number                         { expression.value = number.value }
number -> one                                { number.value = "1" }
number -> two                                { number.value = "2" }
...
number -> nine                               { number.value = "9" }
operator -> plus                             { operator.value = "+" }
operator -> times                            { operator.value = "*" }

Example

Input: three times two plus one

Steps:

- expression(three times two plus one) -> expression(three times two) operator(plus) number(one)
    { expression.value = concat("32*, "1", "+") -> "32*1+"
  - expression(three times two) -> expression(three) operator(times) number(two) { expression.value = concat("3", "2", "*") = "32*" }
    - expression(three) -> number(three)  { expression.value = "3" }
      - number(three) -> three  { number.value = "3" }
    - operator(times) -> times  { operator.value = "*" }
    - number(two) -> two        { number.value = "2" }
  - operator(plus) -> plus { operator.value = "+" }
  - number(one) -> one     { number.value = "1" }

Output: 32*1+

Steps

  • expression(three times two plus one) -> expression(three times two) operator(plus) number(one) { value "3 2 * 2 +" }
    • expression(three times two) -> expression(three) operator(times) number(two) { value = "3 2 *) }
      • expression(three) -> number(three) { value = "3" }
        • number(three) -> three { value = "3" }
      • operator(times) -> times { value = "*" }
      • number(two) -> two { value = "2" }
    • operator(plus) -> plus { value = "+" }
    • number(one) -> two { value = "2" }

Python program

  • Recursive descent, predictive parser
    • One function per nonterminal
    • Lookahead to check which alternative to follow
  • Left recursion elimination (Dragon Book 2.4.5)
    • Left recursion: A -> Aa | b
    • Equivalent without left recursion
      • A -> bR
      • R -> aR | empty
import sys
import os

nums = { "zero" : "1",
         "one" : "1",
         "two" : "2",
         "three" : "3",
         "four" : "4",
         "five" : "5",
         "six" : "6",
         "seven" : "7",
         "eight" : "8",
         "nine" : "9",
       }

ops  = { "plus" : "+",
         "times" : "*",
         "minus" : "-",
         "divide" : "/",
       }

def expression(words):
  n = number(words)
  r = rest(words)
  return n + r

def rest(words):
  lookahead = words.pop(0)
  words.insert(0, lookahead)
  if (lookahead in ops.keys()):
    o = operator(words)
    n = number(words)
    r = rest(words)
    return n + o + r
  else:
    return ""

def number(words):
  return nums[words.pop(0)]

def operator(words):
  return ops[words.pop(0)]


x = input("input string of words: ")
words = x.split(" ")

words.append("$")

print(expression(words))

Order of operations?

Homework

  • Setup ANTLR and test out your setup
    • Start with the LabeledExpr grammar
    • Download ANTLR examples
    • Start with code/tour/LabeledExpr.g4 and code/tour/Calc.java
  • Ask questions on slack for support

Building and running the ANTLR

# add antlr to your classpath; your path to the runtime may vary
export CLASSPATH=/usr/share/java/antlr4-runtime.jar:$CLASSPATH
# this generates the parser
antlr4 -visitor LabeledExpr.g4
# this compiles the calculator
javac LabeledExpr*.java Calc.java EvalVisitor.java
# write an expression to stdin or pass a file
java Calc
# use this to display a parse tree, remove -gui if os is headless
/usr/share/antlr4/grun LabeledExpr prog -gui

Author: Paul Gazzillo

Created: 2023-04-13 Thu 14:59