mirror of
https://github.com/samsonjs/compiler.git
synced 2026-04-27 14:57:45 +00:00
cleaning out the cruft
This commit is contained in:
parent
0c21d1abc6
commit
7aa6fa7d15
4 changed files with 0 additions and 370 deletions
119
cradle.rb
119
cradle.rb
|
|
@ -1,119 +0,0 @@
|
||||||
# A compiler skeleton, or cradle, as described by Jack Crenshaw in his
|
|
||||||
# famous book "Let's Build a Compiler". At least in the beginning,
|
|
||||||
# this code will closely reflect the Pascal code written by Jack.
|
|
||||||
# Over time it may become more idiomatic, however this is an academic
|
|
||||||
# exercise.
|
|
||||||
|
|
||||||
class ParseError < StandardError; end
|
|
||||||
|
|
||||||
class Compiler
|
|
||||||
def initialize(input=STDIN)
|
|
||||||
@look = '' # next lookahead char
|
|
||||||
@input = input # stream to read from
|
|
||||||
|
|
||||||
# seed the lexer
|
|
||||||
get_char
|
|
||||||
end
|
|
||||||
|
|
||||||
# Read the next character from the input stream
|
|
||||||
def get_char
|
|
||||||
@look = @input.getc
|
|
||||||
@look = @look.chr if @look
|
|
||||||
end
|
|
||||||
|
|
||||||
# Report error and halt
|
|
||||||
def abort(msg)
|
|
||||||
raise ParseError, msg
|
|
||||||
end
|
|
||||||
|
|
||||||
# Report what was expected
|
|
||||||
def expected(what)
|
|
||||||
if eof?
|
|
||||||
raise ParseError, "Premature end of file, expected: #{what}."
|
|
||||||
else
|
|
||||||
raise ParseError, "Expected: #{what}, got: #{@look}."
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Match a specific input character
|
|
||||||
def match(char)
|
|
||||||
if @look == char
|
|
||||||
get_char
|
|
||||||
else
|
|
||||||
expected("'#{char}'")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Recognize an alphabetical character
|
|
||||||
def is_alpha(char)
|
|
||||||
('A'..'Z') === char.upcase
|
|
||||||
end
|
|
||||||
|
|
||||||
# Recognize a decimal digit
|
|
||||||
def is_digit(char)
|
|
||||||
('0'..'9') === char
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get an identifier
|
|
||||||
def get_name
|
|
||||||
expected('identifier') unless is_alpha(@look)
|
|
||||||
c = @look
|
|
||||||
get_char
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get a number
|
|
||||||
def get_num
|
|
||||||
expected('integer') unless is_digit(@look)
|
|
||||||
c = @look
|
|
||||||
get_char
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
|
|
||||||
# Print a tab followed by a string and a newline
|
|
||||||
def emit(s)
|
|
||||||
puts "\t#{s}"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse and translate a single mathematical term. Result is in eax.
|
|
||||||
def term
|
|
||||||
emit("mov eax, #{get_num}")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse an addition operator and the 2nd term. The 1st term is
|
|
||||||
# expected in ebx, and is added to the 2nd term leaving the result
|
|
||||||
# in eax.
|
|
||||||
def add
|
|
||||||
match('+')
|
|
||||||
term # result in eax
|
|
||||||
emit("add eax, ebx")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse a subtraction operator and the 2nd term (b). The 1st term
|
|
||||||
# (a) is expected in ebx, and the b is subtracted from a
|
|
||||||
# leaving the result in eax.
|
|
||||||
def subtract
|
|
||||||
match('-')
|
|
||||||
term # result in eax (b)
|
|
||||||
emit("sub eax, ebx") # subtract a from b (this is backwards)
|
|
||||||
emit("neg eax") # fix things up. -(b-a) == a-b
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse and translate a mathematical expression of terms. Result is
|
|
||||||
# in eax.
|
|
||||||
def expression
|
|
||||||
term # result is in eax
|
|
||||||
emit("mov ebx, eax") # move 1st term to ebx (expected by
|
|
||||||
# add & subtract)
|
|
||||||
case @look
|
|
||||||
when '+': add
|
|
||||||
when '-': subtract
|
|
||||||
else
|
|
||||||
expected('Addition or subtraction operator (+ or -)')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def eof?
|
|
||||||
@input.eof? && @look.nil?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
227
interpreter.rb
227
interpreter.rb
|
|
@ -1,227 +0,0 @@
|
||||||
# An interpreter as described by Jack Crenshaw in his famous book
|
|
||||||
# "Let's Build a Compiler". At least in the beginning, this code will
|
|
||||||
# closely reflect the Pascal code written by Jack. Over time it may
|
|
||||||
# become more idiomatic, however this is an academic exercise.
|
|
||||||
#
|
|
||||||
# sjs
|
|
||||||
# may 2009
|
|
||||||
|
|
||||||
class ParseError < StandardError; end
|
|
||||||
|
|
||||||
class Interpreter
|
|
||||||
def initialize(input=STDIN)
|
|
||||||
@look = '' # next lookahead char
|
|
||||||
@input = input # stream to read from
|
|
||||||
@vars = Hash.new(0)
|
|
||||||
|
|
||||||
# seed the lexer
|
|
||||||
get_char
|
|
||||||
end
|
|
||||||
|
|
||||||
def run
|
|
||||||
statement until eof? || @look == '.'
|
|
||||||
end
|
|
||||||
|
|
||||||
# Read the next character from the input stream
|
|
||||||
def get_char
|
|
||||||
@look = if @input.eof?
|
|
||||||
nil
|
|
||||||
else
|
|
||||||
@input.readbyte.chr
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Report error and halt
|
|
||||||
def abort(msg)
|
|
||||||
raise ParseError, msg
|
|
||||||
end
|
|
||||||
|
|
||||||
# Report what was expected
|
|
||||||
def expected(what)
|
|
||||||
msg = if eof?
|
|
||||||
"Premature end of file, expected: #{what}."
|
|
||||||
else
|
|
||||||
"Expected: #{what}, got: #{@look}."
|
|
||||||
end
|
|
||||||
abort(msg)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# Define a variable.
|
|
||||||
def define(name, value=nil)
|
|
||||||
abort("already defined '#{name}'") if @vars.has_key?(name)
|
|
||||||
set(name, value)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Set the value of a variable.
|
|
||||||
def set(name, value)
|
|
||||||
@vars[name] = value
|
|
||||||
end
|
|
||||||
|
|
||||||
# Retrieve the value of a variable.
|
|
||||||
def get(name)
|
|
||||||
abort("undefined variable '#{name}'") unless @vars.has_key?(name)
|
|
||||||
@vars[name]
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# Recognize an alphabetical character.
|
|
||||||
def alpha?(char)
|
|
||||||
('A'..'Z') === char.upcase
|
|
||||||
end
|
|
||||||
|
|
||||||
# Recognize a decimal digit.
|
|
||||||
def digit?(char)
|
|
||||||
('0'..'9') === char
|
|
||||||
end
|
|
||||||
|
|
||||||
# Recognize an alphanumeric character.
|
|
||||||
def alnum?(char)
|
|
||||||
alpha?(char) || digit?(char)
|
|
||||||
end
|
|
||||||
|
|
||||||
def whitespace?(char)
|
|
||||||
char == ' ' || char == '\t'
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# Match a specific input character.
|
|
||||||
def match(char)
|
|
||||||
expected("'#{char}'") unless @look == char
|
|
||||||
get_char
|
|
||||||
skip_whitespace
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse zero or more consecutive characters for which the test is
|
|
||||||
# true.
|
|
||||||
def many(test)
|
|
||||||
token = ''
|
|
||||||
while test.call(@look)
|
|
||||||
token << @look
|
|
||||||
get_char
|
|
||||||
end
|
|
||||||
skip_whitespace
|
|
||||||
token
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get an identifier.
|
|
||||||
def get_name
|
|
||||||
expected('identifier') unless alpha?(@look)
|
|
||||||
many(method(:alpha?))
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get a number.
|
|
||||||
def get_num
|
|
||||||
expected('integer') unless digit?(@look)
|
|
||||||
many(method(:digit?)).to_i
|
|
||||||
end
|
|
||||||
|
|
||||||
# Skip all leading whitespace.
|
|
||||||
def skip_whitespace
|
|
||||||
get_char while whitespace?(@look)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Parse and evaluate a factor.
|
|
||||||
def factor
|
|
||||||
if @look == '('
|
|
||||||
match('(')
|
|
||||||
value = expression
|
|
||||||
match(')')
|
|
||||||
elsif alpha?(@look)
|
|
||||||
value = get(get_name)
|
|
||||||
else
|
|
||||||
value = get_num
|
|
||||||
end
|
|
||||||
value
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse and evaluate a term.
|
|
||||||
def term
|
|
||||||
value = factor
|
|
||||||
while mulop?
|
|
||||||
case @look
|
|
||||||
when '*'
|
|
||||||
match('*')
|
|
||||||
value *= factor
|
|
||||||
when '/'
|
|
||||||
match('/')
|
|
||||||
value /= factor
|
|
||||||
end
|
|
||||||
end
|
|
||||||
value
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse and evaluate a mathematical expression.
|
|
||||||
def expression
|
|
||||||
# Fake unary plus and minus by prepending a 0 to them.
|
|
||||||
value = if addop? then 0 else term end
|
|
||||||
while addop?
|
|
||||||
case @look
|
|
||||||
when '+'
|
|
||||||
match('+')
|
|
||||||
value += term
|
|
||||||
when '-'
|
|
||||||
match('-')
|
|
||||||
value -= term
|
|
||||||
end
|
|
||||||
end
|
|
||||||
value
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse one or more newlines.
|
|
||||||
def newline
|
|
||||||
if @look == "\n" || @look == "\r"
|
|
||||||
get_char while @look == "\n" || @look == "\r"
|
|
||||||
else
|
|
||||||
expected('newline')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse and evaluate an assignment statement.
|
|
||||||
def assignment
|
|
||||||
name = get_name
|
|
||||||
match('=')
|
|
||||||
set(name, expression)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Parse and evaluate any kind of statement.
|
|
||||||
def statement
|
|
||||||
value = case @look
|
|
||||||
when '?': input
|
|
||||||
when '!': output
|
|
||||||
else
|
|
||||||
assignment
|
|
||||||
end
|
|
||||||
newline
|
|
||||||
value
|
|
||||||
end
|
|
||||||
|
|
||||||
# Read and store a number from standard input.
|
|
||||||
def input
|
|
||||||
match('?')
|
|
||||||
set(get_name, gets.to_i)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Print a value to standard output.
|
|
||||||
def output
|
|
||||||
match('!')
|
|
||||||
puts(get(get_name))
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def eof?
|
|
||||||
@input.eof? && @look.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
def addop?
|
|
||||||
@look == '+' || @look == '-'
|
|
||||||
end
|
|
||||||
|
|
||||||
def mulop?
|
|
||||||
@look == '*' || @look == '/'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
BITS 32
|
|
||||||
GLOBAL _main
|
|
||||||
SECTION .data
|
|
||||||
{data}
|
|
||||||
SECTION .bss
|
|
||||||
{bss}
|
|
||||||
SECTION .text
|
|
||||||
_main:
|
|
||||||
{code}
|
|
||||||
;; The result in eax is the exit code, just return.
|
|
||||||
ret
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
BITS 32
|
|
||||||
GLOBAL _start
|
|
||||||
SECTION .data
|
|
||||||
{data}
|
|
||||||
SECTION .bss
|
|
||||||
{bss}
|
|
||||||
SECTION .text
|
|
||||||
_start:
|
|
||||||
{code}
|
|
||||||
;; The result in eax is the exit code, move it to ebx.
|
|
||||||
mov ebx, eax
|
|
||||||
mov eax, 1 ; _exit syscall
|
|
||||||
int 0x80 ; call Linux
|
|
||||||
Loading…
Reference in a new issue