2019-11-03 07:43:37 +00:00
|
|
|
# The Mu computer's level-2 language, also called Mu.
|
2019-10-30 00:51:54 +00:00
|
|
|
# http://akkartik.name/post/mu-2019-2
|
|
|
|
#
|
|
|
|
# To run:
|
|
|
|
# $ ./ntranslate init.linux 0*.subx apps/mu.subx
|
|
|
|
|
2019-11-08 19:32:14 +00:00
|
|
|
# == Goals
|
|
|
|
# 1. Be memory safe. It should be impossible to corrupt the heap, or to create
|
|
|
|
# a bad pointer. (Requires strong type safety.)
|
2019-12-08 21:56:46 +00:00
|
|
|
# 2. Do as little as possible to achieve goal 1. The translator should be
|
|
|
|
# implementable in machine code.
|
2019-11-08 19:32:14 +00:00
|
|
|
# - minimize impedance mismatch between source language and SubX target
|
2019-12-07 19:21:30 +00:00
|
|
|
# (e.g. programmer manages registers manually)
|
|
|
|
# - checks over syntax
|
|
|
|
# (e.g. programmer's register allocation is checked)
|
|
|
|
# - runtime checks to avoid complex static analysis
|
|
|
|
# (e.g. array indexing always checks bounds)
|
2019-11-08 19:32:14 +00:00
|
|
|
|
|
|
|
# == Language description
|
|
|
|
# A program is a sequence of function definitions.
|
|
|
|
#
|
|
|
|
# Function example:
|
|
|
|
# fn foo n: int -> result/eax: int {
|
|
|
|
# ...
|
|
|
|
# }
|
|
|
|
#
|
|
|
|
# Functions consist of a name, optional inputs, optional outputs and a block.
|
|
|
|
#
|
2019-11-09 17:00:42 +00:00
|
|
|
# Function inputs and outputs are variables. All variables have a type and
|
|
|
|
# storage specifier. They can be placed either in memory (on the stack) or in
|
|
|
|
# one of 6 named registers.
|
2019-11-08 19:32:14 +00:00
|
|
|
# eax ecx edx ebx esi edi
|
2019-11-09 17:00:42 +00:00
|
|
|
# Variables in registers must be primitive 32-bit types.
|
2019-11-08 19:32:14 +00:00
|
|
|
# Variables not explicitly placed in a register are on the stack.
|
|
|
|
# Variables in registers need not have a name; in that case you refer to them
|
|
|
|
# directly by the register name.
|
|
|
|
#
|
2019-11-09 17:00:42 +00:00
|
|
|
# Function inputs are always passed in memory (on the stack), while outputs
|
|
|
|
# are always returned in registers.
|
|
|
|
#
|
2019-11-08 19:32:14 +00:00
|
|
|
# Blocks mostly consist of statements.
|
|
|
|
#
|
|
|
|
# Statements mostly consist of a name, optional inputs and optional outputs.
|
|
|
|
#
|
2019-11-09 17:00:42 +00:00
|
|
|
# Statement inputs are variables or literals. Variables need to specify type
|
|
|
|
# (and storage) the first time they're mentioned but not later.
|
2019-11-08 19:32:14 +00:00
|
|
|
#
|
2019-11-09 17:00:42 +00:00
|
|
|
# Statement outputs, like function outputs, must be variables in registers.
|
2019-11-08 19:32:14 +00:00
|
|
|
#
|
|
|
|
# Statement names must be either primitives or user-defined functions.
|
|
|
|
#
|
|
|
|
# Primitives can write to any register.
|
|
|
|
# User-defined functions only write to hard-coded registers. Outputs of each
|
|
|
|
# call must have the same registers as in the function definition.
|
|
|
|
#
|
|
|
|
# There are some other statement types:
|
|
|
|
# - blocks. Multiple statements surrounded by '{...}' and optionally
|
|
|
|
# prefixed with a label name and ':'
|
|
|
|
# - {
|
|
|
|
# ...
|
|
|
|
# }
|
|
|
|
# - foo: {
|
|
|
|
# ...
|
|
|
|
# }
|
|
|
|
#
|
|
|
|
# - variable definitions on the stack. E.g.:
|
2019-12-08 21:56:46 +00:00
|
|
|
# - var foo: (ref int)
|
|
|
|
# - var bar: (ref array int 3)
|
2019-11-08 19:32:14 +00:00
|
|
|
# There's no initializer; variables are automatically initialized.
|
2019-12-08 21:56:46 +00:00
|
|
|
# The type of a local variable is either word-length (4 bytes) or starts with 'ref'.
|
2019-11-08 19:32:14 +00:00
|
|
|
#
|
|
|
|
# - variables definitions in a register. E.g.:
|
|
|
|
# - var foo/eax : int <- add bar 1
|
|
|
|
# The initializer is mandatory and must be a valid instruction that writes
|
|
|
|
# a single output to the right register. In practice registers will
|
|
|
|
# usually be either initialized by primitives or copied from eax.
|
|
|
|
# - var eax : int <- foo bar quux
|
|
|
|
# var floo/ecx : int <- copy eax
|
|
|
|
#
|
|
|
|
# Still todo:
|
|
|
|
# global variables
|
|
|
|
# heap allocations (planned name: 'handle')
|
|
|
|
# user-defined types: 'type' for structs, 'choice' for unions
|
|
|
|
# short-lived 'address' type for efficiently writing inside nested structs
|
2019-11-09 17:34:57 +00:00
|
|
|
#
|
2019-12-08 21:56:46 +00:00
|
|
|
# We don't have 'handle' types yet, but we try to distinguish 'ref', 'handle'
|
|
|
|
# and 'address' in comments. Their definitions are in layer 50, but really you
|
|
|
|
# can ignore the distinctions on a first reading of this program.
|
|
|
|
#
|
2019-11-09 17:34:57 +00:00
|
|
|
# Formal types:
|
|
|
|
# A program is a linked list of functions
|
|
|
|
# A function contains:
|
2019-12-08 21:56:46 +00:00
|
|
|
# name: (handle array byte)
|
2019-11-11 03:09:38 +00:00
|
|
|
# inouts: linked list of vars <-- 'inouts' is more precise than 'inputs'
|
2019-12-08 21:56:46 +00:00
|
|
|
# data: (handle var)
|
|
|
|
# next: (handle list)
|
2019-11-11 03:09:38 +00:00
|
|
|
# outputs: linked list of vars
|
2019-12-08 21:56:46 +00:00
|
|
|
# data: (handle var)
|
|
|
|
# next: (handle list)
|
|
|
|
# body: (handle block)
|
2019-11-09 17:34:57 +00:00
|
|
|
# A var-type contains:
|
2019-12-08 21:56:46 +00:00
|
|
|
# name: (handle array byte)
|
|
|
|
# type: (handle s-expression type-id)
|
2019-11-26 05:00:07 +00:00
|
|
|
#
|
|
|
|
# A statement can be:
|
|
|
|
# tag 0: a block
|
|
|
|
# tag 1: a simple statement
|
|
|
|
# tag 2: a variable defined on the stack
|
|
|
|
# tag 3: a variable defined in a register
|
|
|
|
# tag 4: a named block
|
|
|
|
#
|
|
|
|
# A block contains:
|
|
|
|
# tag: 0
|
2019-12-08 21:56:46 +00:00
|
|
|
# statements: (handle list statement)
|
2019-11-26 05:00:07 +00:00
|
|
|
#
|
|
|
|
# A regular statement contains:
|
|
|
|
# tag: 1
|
2019-12-08 21:56:46 +00:00
|
|
|
# operation: (handle array byte)
|
|
|
|
# inouts: (handle list operand)
|
|
|
|
# outputs: (handle list var)
|
2019-11-26 05:00:07 +00:00
|
|
|
#
|
|
|
|
# A variable defined on the stack contains:
|
|
|
|
# tag: 2
|
2019-12-08 21:56:46 +00:00
|
|
|
# name: (handle array byte)
|
|
|
|
# type: (handle s-expression type-id)
|
2019-11-26 05:00:07 +00:00
|
|
|
#
|
|
|
|
# A variable defined in a register contains:
|
|
|
|
# tag: 3
|
2019-12-08 21:56:46 +00:00
|
|
|
# name: (handle array byte)
|
|
|
|
# type: (handle s-expression type-id)
|
|
|
|
# reg: (handle array byte)
|
2019-11-26 05:00:07 +00:00
|
|
|
#
|
|
|
|
# A named block contains:
|
|
|
|
# tag: 4
|
2019-12-08 21:56:46 +00:00
|
|
|
# name: (handle array byte)
|
|
|
|
# statements: (handle list statement)
|
2019-11-09 17:34:57 +00:00
|
|
|
|
2019-11-15 04:10:49 +00:00
|
|
|
# == Translation: managing the stack
|
2019-11-08 19:32:14 +00:00
|
|
|
# Now that we know what the language looks like in the large, let's think
|
2019-11-15 04:10:49 +00:00
|
|
|
# about how translation happens from the bottom up. One crucial piece of the
|
|
|
|
# puzzle is how Mu will clean up variables defined on the stack for you.
|
2019-11-09 17:00:42 +00:00
|
|
|
#
|
|
|
|
# Assume that we maintain a 'functions' list while parsing source code. And a
|
|
|
|
# 'primitives' list is a global constant. Both these contain enough information
|
|
|
|
# to perform type-checking on function calls or primitive statements, respectively.
|
|
|
|
#
|
|
|
|
# Defining variables pushes them on a stack with the current block depth and
|
2019-11-15 04:10:49 +00:00
|
|
|
# enough information about their location (stack offset or register).
|
2019-11-09 17:00:42 +00:00
|
|
|
# Starting a block increments the current block id.
|
|
|
|
# Each statement now has enough information to emit code for it.
|
|
|
|
# Ending a block is where the magic happens:
|
|
|
|
# pop all variables at the current block depth
|
|
|
|
# emit code to restore all register variables introduced at the current depth
|
|
|
|
# emit code to clean up all stack variables at the current depth (just increment esp)
|
|
|
|
# decrement the current block depth
|
|
|
|
#
|
2019-11-09 17:34:57 +00:00
|
|
|
# Formal types:
|
2019-11-11 03:09:38 +00:00
|
|
|
# live-vars: stack of vars
|
|
|
|
# var:
|
2019-12-08 21:56:46 +00:00
|
|
|
# name: (handle array byte)
|
2019-11-09 17:34:57 +00:00
|
|
|
# type: s-expression? Just a type id for now.
|
|
|
|
# block: int
|
2019-11-15 01:17:34 +00:00
|
|
|
# stack-offset: int (added to ebp)
|
2019-12-08 21:56:46 +00:00
|
|
|
# register: (handle array byte)
|
2019-11-15 01:25:47 +00:00
|
|
|
# either usual register names
|
|
|
|
# or '*' to indicate any register
|
2019-11-15 01:17:34 +00:00
|
|
|
# At most one of stack-offset or register-index must be non-zero.
|
2019-11-15 01:25:47 +00:00
|
|
|
# A register of '*' designates a variable _template_. Only legal in formal
|
|
|
|
# parameters for primitives.
|
2019-11-08 19:32:14 +00:00
|
|
|
|
2019-11-15 04:10:49 +00:00
|
|
|
# == Translating a single function call
|
|
|
|
# This one's easy. Assuming we've already checked things, we just drop the
|
|
|
|
# outputs (which use hard-coded registers) and emit inputs in a standard format.
|
|
|
|
#
|
|
|
|
# out1, out2, out3, ... <- name inout1, inout2, inout3, ...
|
|
|
|
# =>
|
|
|
|
# (subx-name inout1 inout2 inout3)
|
|
|
|
#
|
|
|
|
# Formal types:
|
|
|
|
# functions: linked list of info
|
2019-12-08 21:56:46 +00:00
|
|
|
# name: (handle array byte)
|
2019-11-15 04:10:49 +00:00
|
|
|
# inouts: linked list of vars
|
|
|
|
# outputs: linked list of vars
|
|
|
|
# body: block (singleton linked list)
|
2019-12-08 21:56:46 +00:00
|
|
|
# subx-name: (handle array byte)
|
2019-11-08 19:32:14 +00:00
|
|
|
|
2019-11-15 04:10:49 +00:00
|
|
|
# == Translating a single primitive instruction
|
|
|
|
# A second crucial piece of the puzzle is how Mu converts fairly regular
|
|
|
|
# primitives with their uniform syntax to SubX instructions with their gnarly
|
|
|
|
# x86 details.
|
|
|
|
#
|
|
|
|
# Mu instructions have inputs and outputs. Primitives can have up to 2 of
|
|
|
|
# them.
|
|
|
|
# SubX instructions have rm32 and r32 operands.
|
|
|
|
# The translation between them covers almost all the possibilities.
|
|
|
|
# Instructions with 1 inout may turn into ones with 1 rm32
|
|
|
|
# (e.g. incrementing a var on the stack)
|
|
|
|
# Instructions with 1 output may turn into ones with 1 rm32
|
|
|
|
# (e.g. incrementing a var in a register)
|
|
|
|
# 1 inout and 1 output may turn into 1 rm32 and 1 r32
|
|
|
|
# (e.g. adding a var to a reg)
|
|
|
|
# 2 inouts may turn into 1 rm32 and 1 r32
|
|
|
|
# (e.g. adding a reg to a var)
|
|
|
|
# 1 inout and 1 literal may turn into 1 rm32 and 1 imm32
|
|
|
|
# (e.g. adding a constant to a var)
|
|
|
|
# 1 output and 1 literal may turn into 1 rm32 and 1 imm32
|
|
|
|
# (e.g. adding a constant to a reg)
|
|
|
|
# 2 outputs to hardcoded registers and 1 inout may turn into 1 rm32
|
|
|
|
# (special-case: divide edx:eax by a var or reg)
|
|
|
|
# Observations:
|
|
|
|
# We always emit rm32. It may be the first inout or the first output.
|
|
|
|
# We may emit r32 or imm32 or neither.
|
|
|
|
# When we emit r32 it may come from first inout or second inout or first output.
|
|
|
|
#
|
|
|
|
# Accordingly, the formal data structure for a primitive looks like this:
|
|
|
|
# primitives: linked list of info
|
2019-12-08 21:56:46 +00:00
|
|
|
# name: (handle array byte)
|
2019-11-15 04:10:49 +00:00
|
|
|
# mu-inouts: linked list of vars to check
|
2019-12-26 10:02:57 +00:00
|
|
|
# mu-outputs: linked list of vars to check; at most a singleton
|
2019-12-08 21:56:46 +00:00
|
|
|
# subx-name: (handle array byte)
|
2019-11-16 02:41:45 +00:00
|
|
|
# subx-rm32: enum arg-location
|
|
|
|
# subx-r32: enum arg-location
|
|
|
|
# subx-imm32: enum arg-location
|
2019-12-26 10:02:57 +00:00
|
|
|
# output-is-write-only: boolean
|
2019-11-16 02:41:45 +00:00
|
|
|
# arg-location: enum
|
|
|
|
# 0 means none
|
|
|
|
# 1 means first inout
|
|
|
|
# 2 means second inout
|
|
|
|
# 3 means first output
|
2019-11-09 01:31:11 +00:00
|
|
|
|
2019-11-15 04:10:49 +00:00
|
|
|
# == Translating a block
|
2019-11-09 01:31:11 +00:00
|
|
|
# Emit block name if necessary
|
|
|
|
# Emit '{'
|
|
|
|
# When you encounter a statement, emit it as above
|
|
|
|
# When you encounter a variable declaration
|
|
|
|
# emit any code needed for it (bzeros)
|
|
|
|
# push it on the var stack
|
|
|
|
# update register dict if necessary
|
|
|
|
# When you encounter '}'
|
|
|
|
# While popping variables off the var stack until block id changes
|
|
|
|
# Emit code needed to clean up the stack
|
|
|
|
# either increment esp
|
|
|
|
# or pop into appropriate register
|
|
|
|
|
|
|
|
# The rest is straightforward.
|
|
|
|
|
2019-10-30 00:51:54 +00:00
|
|
|
== data
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
Program: # (handle function)
|
2019-10-30 00:51:54 +00:00
|
|
|
0/imm32
|
|
|
|
|
2019-11-09 20:09:20 +00:00
|
|
|
Function-name:
|
|
|
|
0/imm32
|
2019-11-11 03:09:38 +00:00
|
|
|
Function-subx-name:
|
2019-11-09 20:09:20 +00:00
|
|
|
4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
Function-inouts: # (handle list var)
|
2019-11-09 20:09:20 +00:00
|
|
|
8/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
Function-outputs: # (handle list var)
|
2019-11-09 20:09:20 +00:00
|
|
|
0xc/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
Function-body: # (handle block)
|
2019-11-09 20:09:20 +00:00
|
|
|
0x10/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
Function-next: # (handle function)
|
2019-11-11 03:09:38 +00:00
|
|
|
0x14/imm32
|
2019-11-09 20:09:20 +00:00
|
|
|
Function-size:
|
2019-11-11 03:09:38 +00:00
|
|
|
0x18/imm32/24
|
2019-11-09 20:09:20 +00:00
|
|
|
|
2019-11-15 04:10:49 +00:00
|
|
|
Primitive-name:
|
|
|
|
0/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
Primitive-inouts: # (handle list var)
|
2019-11-16 02:41:45 +00:00
|
|
|
4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
Primitive-outputs: # (handle list var)
|
2019-11-16 02:41:45 +00:00
|
|
|
8/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
Primitive-subx-name: # (handle array byte)
|
2019-11-15 04:10:49 +00:00
|
|
|
0xc/imm32
|
2019-11-16 02:41:45 +00:00
|
|
|
Primitive-subx-rm32: # enum arg-location
|
|
|
|
0x10/imm32
|
|
|
|
Primitive-subx-r32: # enum arg-location
|
2019-11-15 04:10:49 +00:00
|
|
|
0x14/imm32
|
2019-11-16 02:41:45 +00:00
|
|
|
Primitive-subx-imm32: # enum arg-location
|
|
|
|
0x18/imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
Primitive-write-only-output: # boolean
|
2019-11-16 02:41:45 +00:00
|
|
|
0x1c/imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
Primitive-next: # (handle function)
|
|
|
|
0x20/imm32
|
2019-11-15 04:10:49 +00:00
|
|
|
Primitive-size:
|
2019-12-26 10:02:57 +00:00
|
|
|
0x24/imm32/36
|
2019-11-15 04:10:49 +00:00
|
|
|
|
2019-11-26 05:00:07 +00:00
|
|
|
Stmt-tag:
|
|
|
|
0/imm32
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
Block-statements: # (handle list statement)
|
2019-11-26 05:00:07 +00:00
|
|
|
4/imm32
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
Stmt1-operation: # (handle array byte)
|
2019-11-26 05:00:07 +00:00
|
|
|
4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
Stmt1-inouts: # (handle list var)
|
2019-11-26 05:00:07 +00:00
|
|
|
8/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
Stmt1-outputs: # (handle list var)
|
2019-11-26 05:00:07 +00:00
|
|
|
0xc/imm32
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
Vardef-name: # (handle array byte)
|
2019-11-26 05:00:07 +00:00
|
|
|
4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
Vardef-type: # (handle tree type-id)
|
2019-11-26 05:00:07 +00:00
|
|
|
8/imm32
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
Regvardef-name: # (handle array byte)
|
2019-11-26 05:00:07 +00:00
|
|
|
4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
Regvardef-type: # (handle tree type-id)
|
2019-11-26 05:00:07 +00:00
|
|
|
8/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
Regvardef-register: # (handle array byte)
|
2019-11-26 05:00:07 +00:00
|
|
|
0xc/imm32
|
2019-12-26 10:43:14 +00:00
|
|
|
Regvardef-operation: # (handle array byte)
|
|
|
|
0x10/imm32
|
|
|
|
Regvardef-inputs: # (handle list var)
|
|
|
|
0x14/imm32
|
2019-11-26 05:00:07 +00:00
|
|
|
|
|
|
|
Named-block-name:
|
|
|
|
4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
Named-block-statements: # (handle list statement)
|
2019-11-26 05:00:07 +00:00
|
|
|
8/imm32
|
|
|
|
|
2019-11-10 03:04:48 +00:00
|
|
|
Stmt-size:
|
2019-12-26 10:43:14 +00:00
|
|
|
0x18/imm32
|
2019-11-10 03:04:48 +00:00
|
|
|
|
2019-11-09 20:09:20 +00:00
|
|
|
Var-name:
|
|
|
|
0/imm32
|
2019-11-10 03:04:48 +00:00
|
|
|
Var-type:
|
|
|
|
4/imm32
|
2019-11-11 03:09:38 +00:00
|
|
|
Var-block:
|
2019-11-15 01:17:34 +00:00
|
|
|
8/imm32
|
|
|
|
Var-stack-offset:
|
2019-11-10 03:04:48 +00:00
|
|
|
0xc/imm32
|
2019-11-16 02:41:45 +00:00
|
|
|
Var-register:
|
2019-11-10 03:04:48 +00:00
|
|
|
0x10/imm32
|
2019-11-15 01:17:34 +00:00
|
|
|
Var-size:
|
|
|
|
0x14/imm32
|
2019-11-09 20:09:20 +00:00
|
|
|
|
2019-11-16 02:41:45 +00:00
|
|
|
Any-register: # "*"
|
|
|
|
# size
|
|
|
|
1/imm32
|
|
|
|
# data
|
|
|
|
2a/asterisk
|
|
|
|
|
2019-11-29 08:09:06 +00:00
|
|
|
List-value:
|
|
|
|
0/imm32
|
|
|
|
List-next:
|
|
|
|
4/imm32
|
|
|
|
List-size:
|
|
|
|
8/imm32
|
|
|
|
|
2019-10-30 00:51:54 +00:00
|
|
|
== code
|
|
|
|
|
|
|
|
Entry:
|
|
|
|
# . prologue
|
|
|
|
89/<- %ebp 4/r32/esp
|
2019-11-30 19:14:49 +00:00
|
|
|
(new-segment *Heap-size Heap)
|
2019-10-30 00:51:54 +00:00
|
|
|
# if (argv[1] == "test') run-tests()
|
|
|
|
{
|
|
|
|
# if (argc <= 1) break
|
|
|
|
81 7/subop/compare *ebp 1/imm32
|
|
|
|
7e/jump-if-lesser-or-equal break/disp8
|
2019-11-03 07:43:37 +00:00
|
|
|
# if (argv[1] != "test") break
|
2019-10-30 00:51:54 +00:00
|
|
|
(kernel-string-equal? *(ebp+8) "test") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
74/jump-if-equal break/disp8
|
|
|
|
#
|
|
|
|
(run-tests)
|
|
|
|
# syscall(exit, *Num-test-failures)
|
|
|
|
8b/-> *Num-test-failures 3/r32/ebx
|
|
|
|
eb/jump $mu-main:end/disp8
|
|
|
|
}
|
|
|
|
# otherwise convert Stdin
|
|
|
|
(convert-mu Stdin Stdout)
|
|
|
|
(flush Stdout)
|
|
|
|
# syscall(exit, 0)
|
|
|
|
bb/copy-to-ebx 0/imm32
|
|
|
|
$mu-main:end:
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
|
|
|
|
convert-mu: # in : (address buffered-file), out : (address buffered-file)
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
#
|
|
|
|
(parse-mu *(ebp+8))
|
|
|
|
(check-mu-types)
|
|
|
|
(emit-subx *(ebp+0xc))
|
|
|
|
$convert-mu:end:
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-convert-empty-input:
|
|
|
|
# empty input => empty output
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-input-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-input-buffered-file->buffer)
|
2019-10-30 00:51:54 +00:00
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-10-30 00:51:54 +00:00
|
|
|
#
|
|
|
|
(convert-mu _test-input-buffered-file _test-output-buffered-file)
|
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
(check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-convert-function-skeleton:
|
|
|
|
# empty function decl => function prologue and epilogue
|
|
|
|
# fn foo {
|
|
|
|
# }
|
|
|
|
# =>
|
|
|
|
# foo:
|
|
|
|
# # . prologue
|
|
|
|
# 55/push-ebp
|
|
|
|
# 89/<- %ebp 4/r32/esp
|
|
|
|
# # . epilogue
|
|
|
|
# 89/<- %esp 5/r32/ebp
|
|
|
|
# 5d/pop-to-ebp
|
|
|
|
# c3/return
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-input-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-input-buffered-file->buffer)
|
2019-10-30 00:51:54 +00:00
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-10-30 00:51:54 +00:00
|
|
|
#
|
|
|
|
(write _test-input-stream "fn foo {\n")
|
|
|
|
(write _test-input-stream "}\n")
|
|
|
|
# convert
|
|
|
|
(convert-mu _test-input-buffered-file _test-output-buffered-file)
|
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
|
|
|
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-skeleton/0")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-skeleton/1")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-skeleton/2")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-skeleton/3")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-skeleton/4")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-skeleton/5")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-skeleton/6")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-skeleton/7")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-convert-multiple-function-skeletons:
|
|
|
|
# multiple functions correctly organized into a linked list
|
|
|
|
# fn foo {
|
|
|
|
# }
|
|
|
|
# fn bar {
|
|
|
|
# }
|
|
|
|
# =>
|
|
|
|
# foo:
|
|
|
|
# # . prologue
|
|
|
|
# 55/push-ebp
|
|
|
|
# 89/<- %ebp 4/r32/esp
|
|
|
|
# # . epilogue
|
|
|
|
# 89/<- %esp 5/r32/ebp
|
|
|
|
# 5d/pop-to-ebp
|
|
|
|
# c3/return
|
|
|
|
# bar:
|
|
|
|
# # . prologue
|
|
|
|
# 55/push-ebp
|
|
|
|
# 89/<- %ebp 4/r32/esp
|
|
|
|
# # . epilogue
|
|
|
|
# 89/<- %esp 5/r32/ebp
|
|
|
|
# 5d/pop-to-ebp
|
|
|
|
# c3/return
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-input-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-input-buffered-file->buffer)
|
2019-10-30 00:51:54 +00:00
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-10-30 00:51:54 +00:00
|
|
|
#
|
|
|
|
(write _test-input-stream "fn foo {\n")
|
|
|
|
(write _test-input-stream "}\n")
|
|
|
|
(write _test-input-stream "fn bar {\n")
|
|
|
|
(write _test-input-stream "}\n")
|
|
|
|
# convert
|
|
|
|
(convert-mu _test-input-buffered-file _test-output-buffered-file)
|
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check first function
|
|
|
|
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-multiple-function-skeletons/0")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-multiple-function-skeletons/1")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-multiple-function-skeletons/2")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-multiple-function-skeletons/3")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-multiple-function-skeletons/4")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-multiple-function-skeletons/5")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-multiple-function-skeletons/6")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-multiple-function-skeletons/7")
|
|
|
|
# check second function
|
|
|
|
(check-next-stream-line-equal _test-output-stream "bar:" "F - test-convert-multiple-function-skeletons/10")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-multiple-function-skeletons/11")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-multiple-function-skeletons/12")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-multiple-function-skeletons/13")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-multiple-function-skeletons/14")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-multiple-function-skeletons/15")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-multiple-function-skeletons/16")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-multiple-function-skeletons/17")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-08 19:32:14 +00:00
|
|
|
test-convert-function-with-arg:
|
2019-11-28 03:11:16 +00:00
|
|
|
# function with one arg
|
|
|
|
# fn foo n : int {
|
2019-11-08 19:32:14 +00:00
|
|
|
# }
|
|
|
|
# =>
|
|
|
|
# foo:
|
|
|
|
# # . prologue
|
|
|
|
# 55/push-ebp
|
|
|
|
# 89/<- %ebp 4/r32/esp
|
|
|
|
# # . epilogue
|
|
|
|
# 89/<- %esp 5/r32/ebp
|
|
|
|
# 5d/pop-to-ebp
|
|
|
|
# c3/return
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-input-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-input-buffered-file->buffer)
|
2019-11-08 19:32:14 +00:00
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-11-08 19:32:14 +00:00
|
|
|
#
|
2019-11-28 03:11:16 +00:00
|
|
|
(write _test-input-stream "fn foo n : int {\n")
|
2019-11-08 19:32:14 +00:00
|
|
|
(write _test-input-stream "}\n")
|
|
|
|
# convert
|
|
|
|
(convert-mu _test-input-buffered-file _test-output-buffered-file)
|
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
2019-11-29 23:23:22 +00:00
|
|
|
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-arg/0")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-with-arg/1")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-with-arg/2")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-with-arg/3")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-with-arg/4")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-with-arg/5")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-with-arg/6")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-with-arg/7")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-convert-function-with-arg-and-body:
|
|
|
|
# function with one arg and one instruction in the body
|
|
|
|
# fn foo n : int {
|
|
|
|
# increment n
|
|
|
|
# }
|
|
|
|
# =>
|
|
|
|
# foo:
|
|
|
|
# # . prologue
|
|
|
|
# 55/push-ebp
|
|
|
|
# 89/<- %ebp 4/r32/esp
|
|
|
|
# {
|
|
|
|
# ff 0/subop/increment *(ebp+8)
|
|
|
|
# }
|
|
|
|
# # . epilogue
|
|
|
|
# 89/<- %esp 5/r32/ebp
|
|
|
|
# 5d/pop-to-ebp
|
|
|
|
# c3/return
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-input-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-input-buffered-file->buffer)
|
2019-11-29 23:23:22 +00:00
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-11-29 23:23:22 +00:00
|
|
|
#
|
|
|
|
(write _test-input-stream "fn foo n : int {\n")
|
|
|
|
(write _test-input-stream " increment n\n")
|
|
|
|
(write _test-input-stream "}\n")
|
|
|
|
# convert
|
|
|
|
(convert-mu _test-input-buffered-file _test-output-buffered-file)
|
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
|
|
|
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-arg-and-body/0")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-with-arg-and-body/1")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-with-arg-and-body/2")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-with-arg-and-body/3")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-with-arg-and-body/4")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0x00000008)" "F - test-convert-function-with-arg-and-body/5")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-with-arg-and-body/6")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-with-arg-and-body/7")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-with-arg-and-body/8")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-with-arg-and-body/9")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-with-arg-and-body/10")
|
2019-11-08 19:32:14 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-23 07:42:14 +00:00
|
|
|
test-convert-function-distinguishes-args:
|
|
|
|
# function with two args refers to second one in body
|
|
|
|
# fn foo a: int, b: int {
|
|
|
|
# increment b
|
|
|
|
# }
|
|
|
|
# =>
|
|
|
|
# foo:
|
|
|
|
# # . prologue
|
|
|
|
# 55/push-ebp
|
|
|
|
# 89/<- %ebp 4/r32/esp
|
|
|
|
# {
|
|
|
|
# ff 0/subop/increment *(ebp+0xc)
|
|
|
|
# }
|
|
|
|
# # . epilogue
|
|
|
|
# 89/<- %esp 5/r32/ebp
|
|
|
|
# 5d/pop-to-ebp
|
|
|
|
# c3/return
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-input-stream)
|
|
|
|
(clear-stream $_test-input-buffered-file->buffer)
|
|
|
|
(clear-stream _test-output-stream)
|
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
|
|
|
#
|
|
|
|
(write _test-input-stream "fn foo a: int, b: int {\n")
|
|
|
|
(write _test-input-stream " increment b\n")
|
|
|
|
(write _test-input-stream "}\n")
|
|
|
|
# convert
|
|
|
|
(convert-mu _test-input-buffered-file _test-output-buffered-file)
|
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
|
|
|
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-distinguishes-args/0")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-distinguishes-args/1")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-distinguishes-args/2")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-distinguishes-args/3")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-distinguishes-args/4")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0x0000000c)" "F - test-convert-function-distinguishes-args/5")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-distinguishes-args/6")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-distinguishes-args/7")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-distinguishes-args/8")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-distinguishes-args/9")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-distinguishes-args/10")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-28 06:38:06 +00:00
|
|
|
test-convert-function-returns-result:
|
2019-12-28 07:42:35 +00:00
|
|
|
# function writes to output
|
2019-12-28 06:38:06 +00:00
|
|
|
# fn foo a: int -> result/eax: int {
|
|
|
|
# result <- copy a
|
|
|
|
# result <- increment
|
|
|
|
# }
|
|
|
|
# =>
|
|
|
|
# foo:
|
|
|
|
# # . prologue
|
|
|
|
# 55/push-ebp
|
|
|
|
# 89/<- %ebp 4/r32/esp
|
|
|
|
# {
|
|
|
|
# 89/-> *(ebp+8) 0/r32/eax
|
|
|
|
# 40/increment-eax
|
|
|
|
# }
|
|
|
|
# # . epilogue
|
|
|
|
# 89/<- %esp 5/r32/ebp
|
|
|
|
# 5d/pop-to-ebp
|
|
|
|
# c3/return
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-input-stream)
|
|
|
|
(clear-stream $_test-input-buffered-file->buffer)
|
|
|
|
(clear-stream _test-output-stream)
|
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
|
|
|
#
|
|
|
|
(write _test-input-stream "fn foo a: int -> result/eax: int {\n")
|
|
|
|
(write _test-input-stream " result <- copy a\n")
|
|
|
|
(write _test-input-stream " result <- increment\n")
|
|
|
|
(write _test-input-stream "}\n")
|
|
|
|
# convert
|
|
|
|
(convert-mu _test-input-buffered-file _test-output-buffered-file)
|
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
|
|
|
(check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-returns-result/0")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-returns-result/1")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-returns-result/2")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-returns-result/3")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-returns-result/4")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "8b/copy-from *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-returns-result/5")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-convert-function-returns-result/6")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-returns-result/7")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-returns-result/8")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-returns-result/9")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-returns-result/10")
|
|
|
|
(check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-returns-result/11")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-28 00:50:23 +00:00
|
|
|
#######################################################
|
|
|
|
# Parsing
|
|
|
|
#######################################################
|
|
|
|
|
2019-10-30 00:51:54 +00:00
|
|
|
parse-mu: # in : (address buffered-file)
|
|
|
|
# pseudocode
|
2019-12-08 21:56:46 +00:00
|
|
|
# var curr-function : (handle function) = Program
|
|
|
|
# var line : (ref stream byte 512)
|
|
|
|
# var word-slice : (ref slice)
|
2019-10-30 00:51:54 +00:00
|
|
|
# while true # line loop
|
|
|
|
# clear-stream(line)
|
|
|
|
# read-line-buffered(in, line)
|
|
|
|
# if (line->write == 0) break # end of file
|
2019-11-29 23:23:22 +00:00
|
|
|
# word-slice = next-word-or-string(line)
|
|
|
|
# if slice-empty?(word-slice) # end of line
|
|
|
|
# continue
|
|
|
|
# else if slice-starts-with?(word-slice, "#") # comment
|
|
|
|
# continue # end of line
|
|
|
|
# else if slice-equal(word-slice, "fn")
|
2019-12-22 16:11:34 +00:00
|
|
|
# var new-function : (handle function) = allocate(function)
|
|
|
|
# var vars : (ref stack (address var) 256)
|
|
|
|
# populate-mu-function-header(in, new-function, vars)
|
|
|
|
# populate-mu-function-body(in, new-function, vars)
|
|
|
|
# assert(vars->top == 0)
|
2019-11-29 23:23:22 +00:00
|
|
|
# *curr-function = new-function
|
|
|
|
# curr-function = &new-function->next
|
|
|
|
# else
|
|
|
|
# abort()
|
2019-10-30 00:51:54 +00:00
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
|
|
|
51/push-ecx
|
|
|
|
52/push-edx
|
2019-12-22 16:11:34 +00:00
|
|
|
53/push-ebx
|
2019-10-30 00:51:54 +00:00
|
|
|
57/push-edi
|
2019-12-08 21:56:46 +00:00
|
|
|
# var line/ecx : (ref stream byte 512)
|
2019-10-30 00:51:54 +00:00
|
|
|
81 5/subop/subtract %esp 0x200/imm32
|
|
|
|
68/push 0x200/imm32/length
|
|
|
|
68/push 0/imm32/read
|
|
|
|
68/push 0/imm32/write
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var word-slice/edx : (ref slice)
|
2019-10-30 00:51:54 +00:00
|
|
|
68/push 0/imm32/end
|
|
|
|
68/push 0/imm32/start
|
|
|
|
89/<- %edx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var curr-function/edi : (handle function) = Program
|
2019-10-30 00:51:54 +00:00
|
|
|
bf/copy-to-edi Program/imm32
|
2019-12-22 16:11:34 +00:00
|
|
|
# var vars/ebx : (ref stack (address var) 256)
|
|
|
|
81 5/subop/subtract %esp 0x400/imm32
|
|
|
|
68/push 0x400/imm32/length
|
|
|
|
68/push 0/imm32/top
|
|
|
|
89/<- %ebx 4/r32/esp
|
2019-10-30 00:51:54 +00:00
|
|
|
{
|
|
|
|
$parse-mu:line-loop:
|
|
|
|
(clear-stream %ecx)
|
|
|
|
(read-line-buffered *(ebp+8) %ecx)
|
|
|
|
# if (line->write == 0) break
|
|
|
|
81 7/subop/compare *ecx 0/imm32
|
|
|
|
0f 84/jump-if-equal break/disp32
|
|
|
|
#? # dump line {{{
|
2019-11-29 23:23:22 +00:00
|
|
|
#? (write 2 "parse-mu: ^")
|
2019-10-30 00:51:54 +00:00
|
|
|
#? (write-stream 2 %ecx)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream %ecx)
|
|
|
|
#? # }}}
|
2019-11-29 23:23:22 +00:00
|
|
|
(next-word-or-string %ecx %edx)
|
|
|
|
# if slice-empty?(word-slice) continue
|
|
|
|
(slice-empty? %edx)
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
0f 85/jump-if-not-equal loop/disp32
|
|
|
|
# if (*word-slice->start == "#") continue
|
|
|
|
# . eax = *word-slice->start
|
|
|
|
8b/-> *edx 0/r32/eax
|
|
|
|
8a/copy-byte *eax 0/r32/AL
|
|
|
|
81 4/subop/and %eax 0xff/imm32
|
|
|
|
# . if (eax == '#') continue
|
|
|
|
3d/compare-eax-and 0x23/imm32/hash
|
|
|
|
0f 84/jump-if-equal loop/disp32
|
|
|
|
# if (slice-equal?(word-slice, "fn")) parse a function
|
|
|
|
{
|
|
|
|
$parse-mu:fn:
|
|
|
|
(slice-equal? %edx "fn")
|
2019-10-30 00:51:54 +00:00
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
0f 84/jump-if-equal break/disp32
|
2019-12-22 16:11:34 +00:00
|
|
|
# var new-function/eax : (handle function) = populate-mu-function(in, new-function, vars)
|
2019-11-29 23:23:22 +00:00
|
|
|
(allocate Heap *Function-size) # => eax
|
2019-12-22 16:11:34 +00:00
|
|
|
(zero-out %eax *Function-size)
|
2019-12-23 07:20:44 +00:00
|
|
|
(clear-stack %ebx)
|
2019-12-22 16:11:34 +00:00
|
|
|
(populate-mu-function-header %ecx %eax %ebx)
|
|
|
|
(populate-mu-function-body *(ebp+8) %eax %ebx)
|
2019-11-29 23:23:22 +00:00
|
|
|
# *curr-function = new-function
|
|
|
|
89/<- *edi 0/r32/eax
|
|
|
|
# curr-function = &new-function->next
|
|
|
|
8d/address-> *(eax+0x14) 7/r32/edi # Function-next
|
|
|
|
e9/jump $parse-mu:line-loop/disp32
|
|
|
|
}
|
|
|
|
# otherwise abort
|
2019-12-22 16:11:34 +00:00
|
|
|
e9/jump $parse-mu:error1/disp32
|
2019-10-30 00:51:54 +00:00
|
|
|
} # end line loop
|
|
|
|
$parse-mu:end:
|
|
|
|
# . reclaim locals
|
2019-12-22 16:11:34 +00:00
|
|
|
81 0/subop/add %esp 0x630/imm32
|
2019-10-30 00:51:54 +00:00
|
|
|
# . restore registers
|
|
|
|
5f/pop-to-edi
|
2019-12-22 16:11:34 +00:00
|
|
|
5b/pop-to-ebx
|
2019-10-30 00:51:54 +00:00
|
|
|
5a/pop-to-edx
|
|
|
|
59/pop-to-ecx
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-22 16:11:34 +00:00
|
|
|
$parse-mu:error1:
|
2019-10-30 00:51:54 +00:00
|
|
|
# error("unexpected top-level command: " word-slice "\n")
|
|
|
|
(write-buffered Stderr "unexpected top-level command: ")
|
2019-11-29 23:23:22 +00:00
|
|
|
(write-slice-buffered Stderr %edx)
|
2019-10-30 00:51:54 +00:00
|
|
|
(write-buffered Stderr "\n")
|
|
|
|
(flush Stderr)
|
|
|
|
# . syscall(exit, 1)
|
|
|
|
bb/copy-to-ebx 1/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
# never gets here
|
|
|
|
|
2019-12-22 16:11:34 +00:00
|
|
|
$parse-mu:error2:
|
|
|
|
# error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
|
|
|
|
(print-int32-buffered Stderr *ebx)
|
|
|
|
(write-buffered Stderr " vars not reclaimed after fn '")
|
|
|
|
(write-slice-buffered Stderr *eax) # Function-name
|
|
|
|
(write-buffered Stderr "'\n")
|
|
|
|
(flush Stderr)
|
|
|
|
# . syscall(exit, 1)
|
|
|
|
bb/copy-to-ebx 1/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
# never gets here
|
|
|
|
|
2019-11-29 08:09:06 +00:00
|
|
|
# scenarios considered:
|
|
|
|
# ✗ fn foo # no block
|
|
|
|
# ✓ fn foo {
|
|
|
|
# ✗ fn foo { {
|
|
|
|
# ✗ fn foo { }
|
|
|
|
# ✗ fn foo { } {
|
|
|
|
# ✗ fn foo x {
|
|
|
|
# ✗ fn foo x : {
|
|
|
|
# ✓ fn foo x : int {
|
|
|
|
# ✓ fn foo x: int {
|
|
|
|
# ✓ fn foo x: int -> y/eax: int {
|
2019-12-23 07:20:44 +00:00
|
|
|
populate-mu-function-header: # first-line : (address stream byte), out : (handle function), vars : (address stack (handle var))
|
2019-11-29 08:09:06 +00:00
|
|
|
# pseudocode:
|
2019-12-08 21:56:46 +00:00
|
|
|
# var name : (ref slice)
|
|
|
|
# next-word(first-line, name)
|
2019-11-29 08:09:06 +00:00
|
|
|
# assert(name not in '{' '}' '->')
|
|
|
|
# out->name = slice-to-string(name)
|
2019-12-22 16:11:34 +00:00
|
|
|
# var next-offset : int = 8
|
2019-11-29 08:09:06 +00:00
|
|
|
# ## inouts
|
|
|
|
# while true
|
|
|
|
# ## name
|
|
|
|
# name = next-word(first-line)
|
|
|
|
# if (name == '{') goto done
|
|
|
|
# if (name == '->') break
|
|
|
|
# assert(name != '}')
|
2019-12-08 21:56:46 +00:00
|
|
|
# var v : (handle var) = parse-var-with-type(name, first-line)
|
2019-12-22 16:11:34 +00:00
|
|
|
# assert(v->register == null)
|
|
|
|
# v->stack-offset = next-offset
|
2019-12-23 07:20:44 +00:00
|
|
|
# next-offset += size-of(v)
|
2019-11-29 09:24:03 +00:00
|
|
|
# out->inouts = append(out->inouts, v)
|
2019-12-23 07:20:44 +00:00
|
|
|
# push(vars, v)
|
2019-11-29 08:09:06 +00:00
|
|
|
# ## outputs
|
|
|
|
# while true
|
|
|
|
# ## name
|
|
|
|
# name = next-word(first-line)
|
|
|
|
# assert(name not in '{' '}' '->')
|
2019-12-08 21:56:46 +00:00
|
|
|
# var v : (handle var) = parse-var-with-type(name, first-line)
|
2019-12-22 16:11:34 +00:00
|
|
|
# assert(v->register != null)
|
2019-11-29 09:24:03 +00:00
|
|
|
# out->outputs = append(out->outputs, v)
|
2019-11-29 08:09:06 +00:00
|
|
|
# done:
|
|
|
|
#
|
2019-10-30 00:51:54 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
|
|
|
51/push-ecx
|
2019-12-22 16:11:34 +00:00
|
|
|
52/push-edx
|
|
|
|
53/push-ebx
|
2019-10-30 00:51:54 +00:00
|
|
|
57/push-edi
|
|
|
|
# edi = out
|
|
|
|
8b/-> *(ebp+0xc) 7/r32/edi
|
2019-12-08 21:56:46 +00:00
|
|
|
# var word-slice/ecx : (ref slice)
|
2019-10-30 00:51:54 +00:00
|
|
|
68/push 0/imm32/end
|
|
|
|
68/push 0/imm32/start
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-22 16:11:34 +00:00
|
|
|
# var next-offset/edx = 8
|
|
|
|
ba/copy-to-edx 8/imm32
|
2019-11-29 08:09:06 +00:00
|
|
|
# read function name
|
2019-10-30 00:51:54 +00:00
|
|
|
(next-word *(ebp+8) %ecx)
|
2019-11-28 03:11:16 +00:00
|
|
|
# error checking
|
|
|
|
# if (word-slice == '{') abort
|
|
|
|
(slice-equal? %ecx "{") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
2019-12-22 16:11:34 +00:00
|
|
|
0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32
|
2019-11-28 03:11:16 +00:00
|
|
|
# if (word-slice == '->') abort
|
|
|
|
(slice-equal? %ecx "->") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
2019-12-22 16:11:34 +00:00
|
|
|
0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32
|
2019-11-28 03:11:16 +00:00
|
|
|
# if (word-slice == '}') abort
|
|
|
|
(slice-equal? %ecx "}") # => eax
|
2019-10-30 00:51:54 +00:00
|
|
|
3d/compare-eax-and 0/imm32
|
2019-12-22 16:11:34 +00:00
|
|
|
0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32
|
2019-11-29 08:09:06 +00:00
|
|
|
# save function name
|
|
|
|
(slice-to-string Heap %ecx) # => eax
|
|
|
|
89/<- *edi 0/r32/eax # Function-name
|
2019-11-28 03:11:16 +00:00
|
|
|
# save function inouts
|
|
|
|
{
|
2019-12-22 16:11:34 +00:00
|
|
|
$populate-mu-function-header:check-for-inout:
|
2019-11-29 08:09:06 +00:00
|
|
|
(next-word *(ebp+8) %ecx)
|
|
|
|
# if (word-slice == '{') goto done
|
2019-11-28 03:11:16 +00:00
|
|
|
(slice-equal? %ecx "{") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
2019-11-29 08:09:06 +00:00
|
|
|
0f 85/jump-if-not-equal $populate-mu-function-header:done/disp32
|
2019-11-28 03:11:16 +00:00
|
|
|
# if (word-slice == '->') break
|
|
|
|
(slice-equal? %ecx "->") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
2019-12-23 07:20:44 +00:00
|
|
|
0f 85/jump-if-not-equal break/disp32
|
2019-11-28 03:11:16 +00:00
|
|
|
# if (word-slice == '}') abort
|
|
|
|
(slice-equal? %ecx "}") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
2019-12-22 16:11:34 +00:00
|
|
|
0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32
|
2019-12-23 07:20:44 +00:00
|
|
|
# var v/ebx : (handle var) = parse-var-with-type(word-slice, first-line)
|
2019-12-22 16:11:34 +00:00
|
|
|
(parse-var-with-type %ecx *(ebp+8)) # => eax
|
|
|
|
89/<- %ebx 0/r32/eax
|
2019-12-23 07:20:44 +00:00
|
|
|
# assert(v->register == null)
|
2019-12-22 16:11:34 +00:00
|
|
|
81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register
|
|
|
|
0f 85/jump-if-not-equal $populate-mu-function-header:error2/disp32
|
2019-12-23 07:20:44 +00:00
|
|
|
# v->stack-offset = next-offset
|
2019-12-22 16:11:34 +00:00
|
|
|
89/<- *(ebx+0xc) 2/r32/edx # Var-stack-offset
|
2019-12-23 07:20:44 +00:00
|
|
|
# next-offset += size-of(v)
|
2019-12-22 16:11:34 +00:00
|
|
|
(size-of %ebx) # => eax
|
|
|
|
01/add %edx 0/r32/eax
|
2019-11-28 03:11:16 +00:00
|
|
|
#
|
2019-12-22 16:11:34 +00:00
|
|
|
(append-list Heap %ebx *(edi+8)) # Function-inouts => eax
|
2019-11-29 08:09:06 +00:00
|
|
|
89/<- *(edi+8) 0/r32/eax # Function-inouts
|
2019-12-23 07:20:44 +00:00
|
|
|
(push *(ebp+0x10) %ebx)
|
2019-12-22 16:11:34 +00:00
|
|
|
#
|
2019-11-28 03:11:16 +00:00
|
|
|
e9/jump loop/disp32
|
|
|
|
}
|
|
|
|
# save function outputs
|
|
|
|
{
|
2019-12-22 16:11:34 +00:00
|
|
|
$parse-var-with-type:check-for-out:
|
2019-11-29 08:09:06 +00:00
|
|
|
(next-word *(ebp+8) %ecx)
|
2019-11-28 03:11:16 +00:00
|
|
|
# if (word-slice == '{') break
|
|
|
|
(slice-equal? %ecx "{") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
2019-12-22 16:11:34 +00:00
|
|
|
0f 85/jump-if-not-equal break/disp32
|
2019-11-28 03:11:16 +00:00
|
|
|
# if (word-slice == '->') abort
|
|
|
|
(slice-equal? %ecx "->") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
2019-12-22 16:11:34 +00:00
|
|
|
0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32
|
2019-11-28 03:11:16 +00:00
|
|
|
# if (word-slice == '}') abort
|
|
|
|
(slice-equal? %ecx "}") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
2019-12-22 16:11:34 +00:00
|
|
|
0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32
|
2019-11-28 03:11:16 +00:00
|
|
|
#
|
2019-12-22 16:11:34 +00:00
|
|
|
(parse-var-with-type %ecx *(ebp+8)) # => eax
|
|
|
|
89/<- %ebx 0/r32/eax
|
|
|
|
# assert(var->register != null)
|
|
|
|
81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register
|
|
|
|
0f 84/jump-if-equal $populate-mu-function-header:error3/disp32
|
|
|
|
(append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax
|
2019-11-29 08:09:06 +00:00
|
|
|
89/<- *(edi+0xc) 0/r32/eax # Function-outputs
|
2019-11-28 03:11:16 +00:00
|
|
|
e9/jump loop/disp32
|
|
|
|
}
|
2019-11-29 08:09:06 +00:00
|
|
|
$populate-mu-function-header:done:
|
2019-11-29 23:35:28 +00:00
|
|
|
(check-no-tokens-left *(ebp+8))
|
2019-10-30 00:51:54 +00:00
|
|
|
$populate-mu-function-header:end:
|
|
|
|
# . reclaim locals
|
|
|
|
81 0/subop/add %esp 8/imm32
|
|
|
|
# . restore registers
|
|
|
|
5f/pop-to-edi
|
2019-12-22 16:11:34 +00:00
|
|
|
5b/pop-to-ebx
|
|
|
|
5a/pop-to-edx
|
2019-10-30 00:51:54 +00:00
|
|
|
59/pop-to-ecx
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-22 16:11:34 +00:00
|
|
|
$populate-mu-function-header:error1:
|
2019-10-30 00:51:54 +00:00
|
|
|
# error("function header not in form 'fn <name> {'")
|
2019-11-28 03:11:16 +00:00
|
|
|
(write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
|
|
|
|
(flush Stderr)
|
2019-10-30 00:51:54 +00:00
|
|
|
(rewind-stream *(ebp+8))
|
|
|
|
(write-stream 2 *(ebp+8))
|
|
|
|
(write-buffered Stderr "'\n")
|
|
|
|
(flush Stderr)
|
|
|
|
# . syscall(exit, 1)
|
|
|
|
bb/copy-to-ebx 1/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
# never gets here
|
|
|
|
|
2019-12-22 16:11:34 +00:00
|
|
|
$populate-mu-function-header:error2:
|
|
|
|
# error("function input '" var "' cannot be in a register")
|
|
|
|
(write-buffered Stderr "function input '")
|
|
|
|
(write-buffered Stderr *ebx) # Var-name
|
|
|
|
(write-buffered Stderr "' cannot be in a register")
|
|
|
|
(flush Stderr)
|
|
|
|
# . syscall(exit, 1)
|
|
|
|
bb/copy-to-ebx 1/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
# never gets here
|
|
|
|
|
|
|
|
$populate-mu-function-header:error3:
|
|
|
|
# error("function input '" var "' must be in a register")
|
|
|
|
(write-buffered Stderr "function input '")
|
|
|
|
(write-buffered Stderr *eax) # Var-name
|
|
|
|
(write-buffered Stderr " must be in a register'")
|
|
|
|
(flush Stderr)
|
|
|
|
(rewind-stream *(ebp+8))
|
|
|
|
(write-stream 2 *(ebp+8))
|
|
|
|
(write-buffered Stderr "'\n")
|
|
|
|
(flush Stderr)
|
|
|
|
# . syscall(exit, 1)
|
|
|
|
bb/copy-to-ebx 1/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
# never gets here
|
|
|
|
|
2019-11-29 09:24:03 +00:00
|
|
|
test-function-header-with-arg:
|
|
|
|
# 'foo n : int {'
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-input-stream)
|
|
|
|
(write _test-input-stream "foo n : int {\n")
|
2019-12-08 21:56:46 +00:00
|
|
|
# result/ecx : (ref function)
|
2019-11-29 09:24:03 +00:00
|
|
|
2b/subtract-> *Function-size 4/r32/esp
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
(zero-out %ecx *Function-size)
|
2019-12-23 07:20:44 +00:00
|
|
|
# var vars/ebx : (ref stack (address var) 16)
|
|
|
|
81 5/subop/subtract %esp 0x10/imm32
|
|
|
|
68/push 0x10/imm32/length
|
|
|
|
68/push 0/imm32/top
|
|
|
|
89/<- %ebx 4/r32/esp
|
2019-11-29 09:24:03 +00:00
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(populate-mu-function-header _test-input-stream %ecx %ebx)
|
2019-11-29 09:24:03 +00:00
|
|
|
# check result
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal *ecx "foo" "F - test-function-header-with-arg/name") # Function-name
|
2019-12-08 21:56:46 +00:00
|
|
|
# edx : (handle list var) = result->inouts
|
2019-11-29 09:24:03 +00:00
|
|
|
8b/-> *(ecx+8) 2/r32/edx # Function-inouts
|
2019-12-08 21:56:46 +00:00
|
|
|
# ebx : (handle var) = result->inouts->value
|
2019-11-29 09:24:03 +00:00
|
|
|
8b/-> *edx 3/r32/ebx # List-value
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal *ebx "n" "F - test-function-header-with-arg/inout:0") # Var-name
|
2019-11-29 09:24:03 +00:00
|
|
|
(check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:0/type") # Var-type
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-function-header-with-multiple-args:
|
|
|
|
# 'fn foo a: int, b: int, c: int {'
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-input-stream)
|
|
|
|
(write _test-input-stream "foo a: int, b: int c: int {\n")
|
2019-12-08 21:56:46 +00:00
|
|
|
# result/ecx : (handle function)
|
2019-11-29 09:24:03 +00:00
|
|
|
2b/subtract-> *Function-size 4/r32/esp
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
(zero-out %ecx *Function-size)
|
2019-12-23 07:20:44 +00:00
|
|
|
# var vars/ebx : (ref stack (address var) 16)
|
|
|
|
81 5/subop/subtract %esp 0x10/imm32
|
|
|
|
68/push 0x10/imm32/length
|
|
|
|
68/push 0/imm32/top
|
|
|
|
89/<- %ebx 4/r32/esp
|
2019-11-29 09:24:03 +00:00
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(populate-mu-function-header _test-input-stream %ecx %ebx)
|
2019-11-29 09:24:03 +00:00
|
|
|
# check result
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal *ecx "foo") # Function-name
|
2019-12-08 21:56:46 +00:00
|
|
|
# edx : (handle list var) = result->inouts
|
2019-11-29 09:24:03 +00:00
|
|
|
8b/-> *(ecx+8) 2/r32/edx # Function-inouts
|
2019-12-22 16:11:34 +00:00
|
|
|
$test-function-header-with-multiple-args:inout0:
|
2019-12-08 21:56:46 +00:00
|
|
|
# ebx : (handle var) = result->inouts->value
|
2019-11-29 09:24:03 +00:00
|
|
|
8b/-> *edx 3/r32/ebx # List-value
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name
|
2019-12-22 16:11:34 +00:00
|
|
|
(check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:0/type") # Var-type
|
2019-11-29 09:24:03 +00:00
|
|
|
# edx = result->inouts->next
|
|
|
|
8b/-> *(edx+4) 2/r32/edx # List-next
|
2019-12-22 16:11:34 +00:00
|
|
|
$test-function-header-with-multiple-args:inout1:
|
2019-11-29 09:24:03 +00:00
|
|
|
# ebx = result->inouts->next->value
|
|
|
|
8b/-> *edx 3/r32/ebx # List-value
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name
|
2019-12-22 16:11:34 +00:00
|
|
|
(check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:1/type") # Var-type
|
2019-11-29 09:24:03 +00:00
|
|
|
# edx = result->inouts->next->next
|
|
|
|
8b/-> *(edx+4) 2/r32/edx # List-next
|
2019-12-22 16:11:34 +00:00
|
|
|
$test-function-header-with-multiple-args:inout2:
|
2019-11-29 09:24:03 +00:00
|
|
|
# ebx = result->inouts->next->next->value
|
|
|
|
8b/-> *edx 3/r32/ebx # List-value
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name
|
2019-12-22 16:11:34 +00:00
|
|
|
(check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:2/type") # Var-type
|
2019-11-29 09:24:03 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-function-with-multiple-args-and-outputs:
|
|
|
|
# fn foo a: int, b: int, c: int -> x: int, y: int {
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-input-stream)
|
|
|
|
(write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx : int {\n")
|
2019-12-08 21:56:46 +00:00
|
|
|
# result/ecx : (handle function)
|
2019-11-29 09:24:03 +00:00
|
|
|
2b/subtract-> *Function-size 4/r32/esp
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
(zero-out %ecx *Function-size)
|
2019-12-23 07:20:44 +00:00
|
|
|
# var vars/ebx : (ref stack (address var) 16)
|
|
|
|
81 5/subop/subtract %esp 0x10/imm32
|
|
|
|
68/push 0x10/imm32/length
|
|
|
|
68/push 0/imm32/top
|
|
|
|
89/<- %ebx 4/r32/esp
|
2019-11-29 09:24:03 +00:00
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(populate-mu-function-header _test-input-stream %ecx %ebx)
|
2019-11-29 09:24:03 +00:00
|
|
|
# check result
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal *ecx "foo") # Function-name
|
2019-12-08 21:56:46 +00:00
|
|
|
# edx : (handle list var) = result->inouts
|
2019-11-29 09:24:03 +00:00
|
|
|
8b/-> *(ecx+8) 2/r32/edx # Function-inouts
|
2019-12-08 21:56:46 +00:00
|
|
|
# ebx : (handle var) = result->inouts->value
|
2019-11-29 09:24:03 +00:00
|
|
|
8b/-> *edx 3/r32/ebx # List-value
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name
|
2019-11-29 09:24:03 +00:00
|
|
|
(check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:0/type") # Var-type
|
|
|
|
# edx = result->inouts->next
|
|
|
|
8b/-> *(edx+4) 2/r32/edx # List-next
|
|
|
|
# ebx = result->inouts->next->value
|
|
|
|
8b/-> *edx 3/r32/ebx # List-value
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name
|
2019-11-29 09:24:03 +00:00
|
|
|
(check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:1/type") # Var-type
|
|
|
|
# edx = result->inouts->next->next
|
|
|
|
8b/-> *(edx+4) 2/r32/edx # List-next
|
|
|
|
# ebx = result->inouts->next->next->value
|
|
|
|
8b/-> *edx 3/r32/ebx # List-value
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name
|
2019-11-29 09:24:03 +00:00
|
|
|
(check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:2/type") # Var-type
|
2019-12-08 21:56:46 +00:00
|
|
|
# edx : (handle list var) = result->outputs
|
2019-11-29 09:24:03 +00:00
|
|
|
8b/-> *(ecx+0xc) 2/r32/edx # Function-outputs
|
2019-12-08 21:56:46 +00:00
|
|
|
# ebx : (handle var) = result->outputs->value
|
2019-11-29 09:24:03 +00:00
|
|
|
8b/-> *edx 3/r32/ebx # List-value
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal *ebx "x" "F - test-function-header-with-multiple-args/output:0") # Var-name
|
2019-11-29 09:24:03 +00:00
|
|
|
(check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/output:0/type") # Var-type
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal *(ebx+0x10) "ecx" "F - test-function-header-with-arg/output:0/register") # Var-register
|
2019-11-29 09:24:03 +00:00
|
|
|
# edx = result->outputs->next
|
|
|
|
8b/-> *(edx+4) 2/r32/edx # List-next
|
|
|
|
# ebx = result->outputs->next->value
|
|
|
|
8b/-> *edx 3/r32/ebx # List-value
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal *ebx "y" "F - test-function-header-with-multiple-args/output:1") # Var-name
|
2019-11-29 09:24:03 +00:00
|
|
|
(check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/output:1/type") # Var-type
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal *(ebx+0x10) "edx" "F - test-function-header-with-arg/output:0/register") # Var-register
|
2019-11-29 09:24:03 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-29 07:20:39 +00:00
|
|
|
# format for variables with types
|
|
|
|
# x : int
|
|
|
|
# x: int
|
2019-11-29 08:31:29 +00:00
|
|
|
# x: int,
|
|
|
|
# ignores at most one trailing colon or comma
|
2019-12-08 21:56:46 +00:00
|
|
|
parse-var-with-type: # name: (address slice), first-line: (address stream byte) -> result/eax: (handle var)
|
2019-11-29 07:20:39 +00:00
|
|
|
# pseudocode:
|
2019-12-08 21:56:46 +00:00
|
|
|
# var v : (handle var) = allocate(Heap, Var-size)
|
|
|
|
# var s : (ref slice)
|
2019-11-29 07:20:39 +00:00
|
|
|
# next-token-from-slice(name->start, name->end, '/', s)
|
2019-12-08 21:56:46 +00:00
|
|
|
# var end : (address byte) = s->end
|
2019-11-29 07:20:39 +00:00
|
|
|
# if (slice-ends-with(s, ":"))
|
|
|
|
# decrement s->end
|
2019-11-29 08:31:29 +00:00
|
|
|
# if (slice-ends-with(s, ","))
|
|
|
|
# decrement s->end
|
2019-11-29 07:20:39 +00:00
|
|
|
# v->name = slice-to-string(s)
|
|
|
|
# ## register
|
2019-11-29 08:43:10 +00:00
|
|
|
# next-token-from-slice(end, name->end, '/', s)
|
2019-11-29 08:31:29 +00:00
|
|
|
# if (slice-ends-with(s, ":"))
|
|
|
|
# decrement s->end
|
|
|
|
# if (slice-ends-with(s, ","))
|
|
|
|
# decrement s->end
|
2019-11-29 07:20:39 +00:00
|
|
|
# if (!slice-empty?(s))
|
|
|
|
# v->register = slice-to-string(s)
|
|
|
|
# ## type
|
2019-11-29 08:43:10 +00:00
|
|
|
# s = next-mu-token(first-line)
|
2019-11-29 08:31:29 +00:00
|
|
|
# assert(s not in '{' '}' '->')
|
|
|
|
# if (slice-empty?(s)) {
|
2019-11-29 08:43:10 +00:00
|
|
|
# s = next-mu-token(first-line)
|
2019-11-29 07:20:39 +00:00
|
|
|
# assert(type not in '{' '}' '->')
|
|
|
|
# }
|
|
|
|
# type = type-for(s)
|
|
|
|
# v->type = type
|
|
|
|
# return v
|
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
52/push-edx
|
|
|
|
53/push-ebx
|
|
|
|
56/push-esi
|
|
|
|
57/push-edi
|
2019-12-08 21:56:46 +00:00
|
|
|
# var result/edi : (handle var) = allocate(Heap, Var-size)
|
2019-12-22 16:11:34 +00:00
|
|
|
(allocate Heap *Var-size) # => eax
|
|
|
|
(zero-out %eax *Var-size)
|
2019-11-29 07:20:39 +00:00
|
|
|
89/<- %edi 0/r32/eax
|
|
|
|
# esi = name
|
|
|
|
8b/-> *(ebp+8) 6/r32/esi
|
2019-12-08 21:56:46 +00:00
|
|
|
# var s/ecx : (ref slice)
|
2019-11-29 07:20:39 +00:00
|
|
|
68/push 0/imm32/end
|
|
|
|
68/push 0/imm32/start
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-22 16:11:34 +00:00
|
|
|
$parse-var-with-type:save-name:
|
2019-11-29 07:20:39 +00:00
|
|
|
# save v->name
|
|
|
|
(next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/'
|
|
|
|
# . end/edx = s->end
|
|
|
|
8b/-> *(ecx+4) 2/r32/edx
|
|
|
|
# . if s ends with ':', decrement s->end
|
|
|
|
{
|
|
|
|
8b/-> *(ecx+4) 0/r32/eax
|
|
|
|
48/decrement-eax
|
|
|
|
8a/copy-byte *eax 3/r32/BL
|
|
|
|
81 4/subop/and %ebx 0xff/imm32
|
|
|
|
81 7/subop/compare %ebx 0x3a/imm32/colon
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
89/<- *(ecx+4) 0/r32/eax
|
|
|
|
}
|
2019-11-29 08:31:29 +00:00
|
|
|
# . if s ends with ',', decrement s->end
|
|
|
|
{
|
|
|
|
8b/-> *(ecx+4) 0/r32/eax
|
|
|
|
48/decrement-eax
|
|
|
|
8a/copy-byte *eax 3/r32/BL
|
|
|
|
81 4/subop/and %ebx 0xff/imm32
|
|
|
|
81 7/subop/compare %ebx 0x2c/imm32/comma
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
89/<- *(ecx+4) 0/r32/eax
|
|
|
|
}
|
2019-12-22 16:11:34 +00:00
|
|
|
$parse-var-with-type:write-name:
|
2019-11-29 07:20:39 +00:00
|
|
|
(slice-to-string Heap %ecx) # => eax
|
|
|
|
89/<- *edi 0/r32/eax # Var-name
|
|
|
|
# save v->register
|
2019-12-22 16:11:34 +00:00
|
|
|
$parse-var-with-type:save-register:
|
2019-11-29 07:20:39 +00:00
|
|
|
(next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/'
|
2019-11-29 08:31:29 +00:00
|
|
|
# . if s ends with ':', decrement s->end
|
|
|
|
{
|
|
|
|
8b/-> *(ecx+4) 0/r32/eax
|
|
|
|
48/decrement-eax
|
|
|
|
8a/copy-byte *eax 3/r32/BL
|
|
|
|
81 4/subop/and %ebx 0xff/imm32
|
|
|
|
81 7/subop/compare %ebx 0x3a/imm32/colon
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
89/<- *(ecx+4) 0/r32/eax
|
|
|
|
}
|
|
|
|
# . if s ends with ',', decrement s->end
|
|
|
|
{
|
|
|
|
8b/-> *(ecx+4) 0/r32/eax
|
|
|
|
48/decrement-eax
|
|
|
|
8a/copy-byte *eax 3/r32/BL
|
|
|
|
81 4/subop/and %ebx 0xff/imm32
|
|
|
|
81 7/subop/compare %ebx 0x2c/imm32/comma
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
89/<- *(ecx+4) 0/r32/eax
|
|
|
|
}
|
2019-11-29 07:20:39 +00:00
|
|
|
# if (!slice-empty?(s)) v->register = slice-to-string(s)
|
|
|
|
{
|
2019-12-22 16:11:34 +00:00
|
|
|
$parse-var-with-type:write-register:
|
|
|
|
# HACK: s->end can be less than s->start with all the decrements above
|
|
|
|
# That's probably a sign we have the wrong algorithm for this function.
|
|
|
|
8b/-> *ecx 0/r32/eax
|
|
|
|
39/compare 0/r32/eax *(ecx+4)
|
|
|
|
76/jump-if-lesser-or-equal break/disp8
|
2019-11-29 07:20:39 +00:00
|
|
|
(slice-to-string Heap %ecx)
|
|
|
|
89/<- *(edi+0x10) 0/r32/eax # Var-register
|
|
|
|
}
|
|
|
|
# save v->type
|
2019-11-29 08:43:10 +00:00
|
|
|
(next-mu-token *(ebp+0xc) %ecx)
|
2019-11-29 07:20:39 +00:00
|
|
|
# if (word-slice == '{') abort
|
|
|
|
(slice-equal? %ecx "{") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32
|
|
|
|
# if (word-slice == '->') abort
|
|
|
|
(slice-equal? %ecx "->") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32
|
|
|
|
# if (word-slice == '}') abort
|
|
|
|
(slice-equal? %ecx "}") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32
|
2019-11-29 08:31:29 +00:00
|
|
|
# if (slice-empty?(type)) skip
|
|
|
|
(slice-empty? %ecx)
|
2019-11-29 07:20:39 +00:00
|
|
|
{
|
|
|
|
3d/compare-eax-and 0/imm32
|
2019-11-29 08:09:06 +00:00
|
|
|
0f 84/jump-if-equal break/disp32
|
2019-11-29 08:43:10 +00:00
|
|
|
(next-mu-token *(ebp+0xc) %ecx)
|
2019-11-29 07:20:39 +00:00
|
|
|
# if (word-slice == '{') abort
|
|
|
|
(slice-equal? %ecx "{") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32
|
|
|
|
# if (word-slice == '->') abort
|
|
|
|
(slice-equal? %ecx "->") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32
|
|
|
|
# if (word-slice == '}') abort
|
|
|
|
(slice-equal? %ecx "}") # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32
|
|
|
|
}
|
|
|
|
(type-for %ecx)
|
|
|
|
89/<- *(edi+4) 0/r32/eax # Var-type
|
|
|
|
$parse-var-with-type:end:
|
|
|
|
# return result
|
|
|
|
89/<- %eax 7/r32/edi
|
2019-11-29 08:09:06 +00:00
|
|
|
# . reclaim locals
|
|
|
|
81 0/subop/add %esp 8/imm32
|
2019-11-29 07:20:39 +00:00
|
|
|
# . restore registers
|
|
|
|
5f/pop-to-edi
|
|
|
|
5e/pop-to-esi
|
|
|
|
5b/pop-to-ebx
|
|
|
|
5a/pop-to-edx
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
$parse-var-with-type:abort:
|
|
|
|
# error("function header not in form 'fn <name> {'")
|
|
|
|
(write-buffered Stderr "var should have form 'name: type' in '")
|
|
|
|
(flush Stderr)
|
|
|
|
(rewind-stream *(ebp+0xc))
|
|
|
|
(write-stream 2 *(ebp+0xc))
|
|
|
|
(write-buffered Stderr "'\n")
|
|
|
|
(flush Stderr)
|
|
|
|
# . syscall(exit, 1)
|
|
|
|
bb/copy-to-ebx 1/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
# never gets here
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
next-mu-token: # in: (address stream byte), out: (address slice)
|
2019-11-29 08:43:10 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
|
|
|
57/push-edi
|
|
|
|
# edi = out
|
|
|
|
8b/-> *(ebp+0xc) 7/r32/edi
|
|
|
|
#
|
|
|
|
(next-word *(ebp+8) %edi) # TODO: support s-expressions
|
|
|
|
# if out ends with ':', decrement out->end
|
|
|
|
{
|
|
|
|
8b/-> *(edi+4) 0/r32/eax
|
|
|
|
48/decrement-eax
|
|
|
|
8a/copy-byte *eax 3/r32/BL
|
|
|
|
81 4/subop/and %ebx 0xff/imm32
|
|
|
|
81 7/subop/compare %ebx 0x3a/imm32/colon
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
89/<- *(edi+4) 0/r32/eax
|
|
|
|
}
|
|
|
|
# if out ends with ',', decrement out->end
|
|
|
|
{
|
|
|
|
8b/-> *(edi+4) 0/r32/eax
|
|
|
|
48/decrement-eax
|
|
|
|
8a/copy-byte *eax 3/r32/BL
|
|
|
|
81 4/subop/and %ebx 0xff/imm32
|
|
|
|
81 7/subop/compare %ebx 0x2c/imm32/comma
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
89/<- *(edi+4) 0/r32/eax
|
|
|
|
}
|
|
|
|
$next-mu-token:end:
|
|
|
|
b8/copy-to-eax 1/imm32/int
|
|
|
|
# . restore registers
|
|
|
|
5f/pop-to-edi
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
type-for: # name: (address slice) -> result/eax: (handle s-expression type-id)
|
2019-11-29 07:20:39 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
2019-11-29 08:31:29 +00:00
|
|
|
#? (write-buffered Stderr "type: ")
|
|
|
|
#? (write-slice-buffered Stderr *(ebp+8))
|
|
|
|
#? (write-buffered Stderr Newline)
|
|
|
|
#? (flush Stderr)
|
2019-11-29 07:20:39 +00:00
|
|
|
$type-for:end:
|
|
|
|
b8/copy-to-eax 1/imm32/int
|
|
|
|
# . restore registers
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-parse-var-with-type:
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "x:"
|
|
|
|
b8/copy-to-eax "x:"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-29 07:20:39 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
# _test-input-stream contains "int"
|
|
|
|
(clear-stream _test-input-stream)
|
|
|
|
(write _test-input-stream "int")
|
|
|
|
#
|
2019-11-29 08:31:29 +00:00
|
|
|
(parse-var-with-type %ecx _test-input-stream)
|
2019-11-29 07:20:39 +00:00
|
|
|
8b/-> *eax 2/r32/edx # Var-name
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal %edx "x" "F - test-var-with-type/name")
|
2019-11-29 07:20:39 +00:00
|
|
|
8b/-> *(eax+4) 2/r32/edx # Var-type
|
|
|
|
(check-ints-equal %edx 1 "F - test-var-with-type/type")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-parse-var-with-type-and-register:
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "x/eax"
|
|
|
|
b8/copy-to-eax "x/eax"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-29 07:20:39 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
# _test-input-stream contains ": int"
|
|
|
|
(clear-stream _test-input-stream)
|
|
|
|
(write _test-input-stream ": int")
|
|
|
|
#
|
2019-11-29 08:31:29 +00:00
|
|
|
(parse-var-with-type %ecx _test-input-stream)
|
2019-11-29 07:20:39 +00:00
|
|
|
8b/-> *eax 2/r32/edx # Var-name
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal %edx "x" "F - test-var-with-type-and-register/name")
|
2019-11-29 07:20:39 +00:00
|
|
|
8b/-> *(eax+0x10) 2/r32/edx # Var-register
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register")
|
2019-11-29 07:20:39 +00:00
|
|
|
8b/-> *(eax+4) 2/r32/edx # Var-type
|
|
|
|
(check-ints-equal %edx 1 "F - test-var-with-type-and-register/type")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-29 08:31:29 +00:00
|
|
|
test-parse-var-with-trailing-characters:
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
2019-12-22 16:11:34 +00:00
|
|
|
# (eax..ecx) = "x:"
|
|
|
|
b8/copy-to-eax "x:"/imm32
|
2019-11-29 08:31:29 +00:00
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-29 08:31:29 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
# _test-input-stream contains "int,"
|
|
|
|
(clear-stream _test-input-stream)
|
|
|
|
(write _test-input-stream "int,")
|
|
|
|
#
|
|
|
|
(parse-var-with-type %ecx _test-input-stream)
|
|
|
|
8b/-> *eax 2/r32/edx # Var-name
|
2019-11-29 09:27:39 +00:00
|
|
|
(check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name")
|
2019-11-29 08:31:29 +00:00
|
|
|
8b/-> *(eax+0x10) 2/r32/edx # Var-register
|
2019-12-22 16:11:34 +00:00
|
|
|
(check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register")
|
2019-11-29 08:31:29 +00:00
|
|
|
8b/-> *(eax+4) 2/r32/edx # Var-type
|
|
|
|
(check-ints-equal %edx 1 "F - test-var-with-trailing-characters/type")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-22 16:11:34 +00:00
|
|
|
test-parse-var-with-register-and-trailing-characters:
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "x/eax:"
|
|
|
|
b8/copy-to-eax "x/eax:"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
# _test-input-stream contains "int,"
|
|
|
|
(clear-stream _test-input-stream)
|
|
|
|
(write _test-input-stream "int,")
|
|
|
|
#
|
|
|
|
(parse-var-with-type %ecx _test-input-stream)
|
|
|
|
8b/-> *eax 2/r32/edx # Var-name
|
|
|
|
(check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name")
|
|
|
|
8b/-> *(eax+0x10) 2/r32/edx # Var-register
|
|
|
|
(check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register")
|
|
|
|
8b/-> *(eax+4) 2/r32/edx # Var-type
|
|
|
|
(check-ints-equal %edx 1 "F - test-var-with-register-and-trailing-characters/type")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-28 09:01:37 +00:00
|
|
|
# identifier starts with a letter or '$' or '_'
|
|
|
|
# no constraints at the moment on later letters
|
|
|
|
# all we really want to do so far is exclude '{', '}' and '->'
|
|
|
|
is-identifier?: # in : (address slice) -> result/eax : boolean
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# if (slice-empty?(in)) return false
|
|
|
|
(slice-empty? *(ebp+8)) # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
75/jump-if-not-equal $is-identifier?:false/disp8
|
2019-12-08 21:56:46 +00:00
|
|
|
# var c/eax : byte = *in->start
|
2019-11-28 09:01:37 +00:00
|
|
|
8b/-> *(ebp+8) 0/r32/eax
|
|
|
|
8b/-> *eax 0/r32/eax
|
|
|
|
8a/copy-byte *eax 0/r32/AL
|
|
|
|
81 4/subop/and %eax 0xff/imm32
|
|
|
|
# if (c == '$') return true
|
|
|
|
3d/compare-eax-and 0x24/imm32/$
|
|
|
|
74/jump-if-equal $is-identifier?:true/disp8
|
|
|
|
# if (c == '_') return true
|
|
|
|
3d/compare-eax-and 0x5f/imm32/_
|
|
|
|
74/jump-if-equal $is-identifier?:true/disp8
|
|
|
|
# drop case
|
|
|
|
25/and-eax-with 0x5f/imm32
|
|
|
|
# if (c < 'A') return false
|
|
|
|
3d/compare-eax-and 0x41/imm32/A
|
|
|
|
7c/jump-if-lesser $is-identifier?:false/disp8
|
|
|
|
# if (c > 'Z') return false
|
|
|
|
3d/compare-eax-and 0x5a/imm32/Z
|
|
|
|
7f/jump-if-greater $is-identifier?:false/disp8
|
|
|
|
# otherwise return true
|
|
|
|
$is-identifier?:true:
|
|
|
|
b8/copy-to-eax 1/imm32/true
|
|
|
|
eb/jump $is-identifier?:end/disp8
|
|
|
|
$is-identifier?:false:
|
|
|
|
b8/copy-to-eax 0/imm32/false
|
|
|
|
$is-identifier?:end:
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-is-identifier-dollar:
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "$a"
|
|
|
|
b8/copy-to-eax "$a"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-28 09:01:37 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
#
|
|
|
|
(is-identifier? %ecx)
|
|
|
|
(check-ints-equal %eax 1 "F - test-is-identifier-dollar")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-is-identifier-underscore:
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "_a"
|
|
|
|
b8/copy-to-eax "_a"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-28 09:01:37 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
#
|
|
|
|
(is-identifier? %ecx)
|
|
|
|
(check-ints-equal %eax 1 "F - test-is-identifier-underscore")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-is-identifier-a:
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "a$"
|
|
|
|
b8/copy-to-eax "a$"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-28 09:01:37 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
#
|
|
|
|
(is-identifier? %ecx)
|
|
|
|
(check-ints-equal %eax 1 "F - test-is-identifier-a")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-is-identifier-z:
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "z$"
|
|
|
|
b8/copy-to-eax "z$"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-28 09:01:37 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
#
|
|
|
|
(is-identifier? %ecx)
|
|
|
|
(check-ints-equal %eax 1 "F - test-is-identifier-z")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-is-identifier-A:
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "A$"
|
|
|
|
b8/copy-to-eax "A$"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-28 09:01:37 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
#
|
|
|
|
(is-identifier? %ecx)
|
|
|
|
(check-ints-equal %eax 1 "F - test-is-identifier-A")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-is-identifier-Z:
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "Z$"
|
|
|
|
b8/copy-to-eax "Z$"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-28 09:01:37 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
#
|
|
|
|
(is-identifier? %ecx)
|
|
|
|
(check-ints-equal %eax 1 "F - test-is-identifier-Z")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-is-identifier-@:
|
2019-11-28 09:13:44 +00:00
|
|
|
# character before 'A' is invalid
|
2019-11-28 09:01:37 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "@a"
|
|
|
|
b8/copy-to-eax "@a"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-28 09:01:37 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
#
|
|
|
|
(is-identifier? %ecx)
|
|
|
|
(check-ints-equal %eax 0 "F - test-is-identifier-@")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-28 09:13:44 +00:00
|
|
|
test-is-identifier-square-bracket:
|
|
|
|
# character after 'Z' is invalid
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "[a"
|
|
|
|
b8/copy-to-eax "[a"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-28 09:13:44 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
#
|
|
|
|
(is-identifier? %ecx)
|
|
|
|
(check-ints-equal %eax 0 "F - test-is-identifier-@")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-is-identifier-backtick:
|
|
|
|
# character before 'a' is invalid
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "`a"
|
|
|
|
b8/copy-to-eax "`a"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-28 09:13:44 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
#
|
|
|
|
(is-identifier? %ecx)
|
|
|
|
(check-ints-equal %eax 0 "F - test-is-identifier-backtick")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-is-identifier-curly-brace-open:
|
|
|
|
# character after 'z' is invalid; also used for blocks
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "{a"
|
|
|
|
b8/copy-to-eax "{a"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-28 09:13:44 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
#
|
|
|
|
(is-identifier? %ecx)
|
|
|
|
(check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-is-identifier-curly-brace-close:
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "}a"
|
|
|
|
b8/copy-to-eax "}a"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-28 09:13:44 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
#
|
|
|
|
(is-identifier? %ecx)
|
|
|
|
(check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-is-identifier-hyphen:
|
|
|
|
# disallow leading '-' since '->' has special meaning
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# (eax..ecx) = "-a"
|
|
|
|
b8/copy-to-eax "-a"/imm32
|
|
|
|
8b/-> *eax 1/r32/ecx
|
|
|
|
8d/copy-address *(eax+ecx+4) 1/r32/ecx
|
|
|
|
05/add-to-eax 4/imm32
|
2019-12-08 21:56:46 +00:00
|
|
|
# var slice/ecx : (ref slice) = {eax, ecx}
|
2019-11-28 09:13:44 +00:00
|
|
|
51/push-ecx
|
|
|
|
50/push-eax
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
#
|
|
|
|
(is-identifier? %ecx)
|
|
|
|
(check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-23 07:20:44 +00:00
|
|
|
populate-mu-function-body: # in : (address buffered-file), out : (handle function), vars : (address stack (handle var))
|
2019-11-26 05:04:23 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
|
|
|
56/push-esi
|
2019-11-30 20:26:30 +00:00
|
|
|
57/push-edi
|
2019-11-26 05:04:23 +00:00
|
|
|
# esi = in
|
|
|
|
8b/-> *(ebp+8) 6/r32/esi
|
2019-11-30 20:26:30 +00:00
|
|
|
# edi = out
|
|
|
|
8b/-> *(ebp+0xc) 7/r32/edi
|
2019-12-23 07:20:44 +00:00
|
|
|
# var eax : (handle block) = parse-mu-block(in, vars)
|
2019-12-28 06:38:06 +00:00
|
|
|
(parse-mu-block %esi *(ebp+0x10) %edi) # => eax
|
2019-11-26 05:04:23 +00:00
|
|
|
# out->body = eax
|
2019-11-30 20:26:30 +00:00
|
|
|
89/<- *(edi+0x10) 0/r32/eax # Function-body
|
2019-11-26 05:04:23 +00:00
|
|
|
$populate-mu-function-body:end:
|
|
|
|
# . restore registers
|
2019-11-30 20:26:30 +00:00
|
|
|
5f/pop-to-edi
|
2019-11-26 05:04:23 +00:00
|
|
|
5e/pop-to-esi
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
# parses a block, assuming that the leading '{' has already been read by the caller
|
2019-12-28 06:38:06 +00:00
|
|
|
parse-mu-block: # in : (address buffered-file), vars : (address stack (handle var)), fn : (handle function) -> result/eax : (handle block)
|
2019-11-29 23:23:22 +00:00
|
|
|
# pseudocode:
|
2019-12-08 21:56:46 +00:00
|
|
|
# var line : (ref stream byte 512)
|
|
|
|
# var word-slice : (ref slice)
|
2019-11-29 23:23:22 +00:00
|
|
|
# result/eax = allocate(Heap, Stmt-size)
|
|
|
|
# result->tag = 0/Block
|
|
|
|
# while true # line loop
|
|
|
|
# clear-stream(line)
|
|
|
|
# read-line-buffered(in, line)
|
|
|
|
# if (line->write == 0) break # end of file
|
|
|
|
# word-slice = next-word(line)
|
|
|
|
# if slice-empty?(word-slice) # end of line
|
|
|
|
# continue
|
|
|
|
# else if slice-starts-with?(word-slice, "#")
|
|
|
|
# continue
|
|
|
|
# else if slice-equal?(word-slice, "{")
|
2019-11-29 23:35:28 +00:00
|
|
|
# assert(no-tokens-in(line))
|
2019-12-28 06:38:06 +00:00
|
|
|
# block = parse-mu-block(in, vars, fn)
|
2019-11-29 23:23:22 +00:00
|
|
|
# append-to-block(result, block)
|
|
|
|
# else if slice-equal?(word-slice, "}")
|
|
|
|
# break
|
|
|
|
# else if slice-ends-with?(word-slice, ":")
|
2019-12-28 06:38:06 +00:00
|
|
|
# named-block = parse-mu-named-block(word-slice, line, in, vars, fn)
|
2019-11-29 23:23:22 +00:00
|
|
|
# append-to-block(result, named-block)
|
|
|
|
# else if slice-equal?(word-slice, "var")
|
2019-12-23 07:20:44 +00:00
|
|
|
# var-def = parse-mu-var-def(line, vars)
|
2019-11-29 23:23:22 +00:00
|
|
|
# append-to-block(result, var-def)
|
|
|
|
# else
|
2019-12-28 06:38:06 +00:00
|
|
|
# stmt = parse-mu-stmt(line, vars, fn)
|
2019-11-29 23:23:22 +00:00
|
|
|
# append-to-block(result, stmt)
|
|
|
|
# return result
|
|
|
|
#
|
2019-10-30 00:51:54 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
52/push-edx
|
|
|
|
53/push-ebx
|
2019-11-30 20:26:30 +00:00
|
|
|
57/push-edi
|
2019-12-08 21:56:46 +00:00
|
|
|
# var line/ecx : (ref stream byte 512)
|
2019-10-30 00:51:54 +00:00
|
|
|
81 5/subop/subtract %esp 0x200/imm32
|
|
|
|
68/push 0x200/imm32/length
|
|
|
|
68/push 0/imm32/read
|
|
|
|
68/push 0/imm32/write
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var word-slice/edx : (ref slice)
|
2019-10-30 00:51:54 +00:00
|
|
|
68/push 0/imm32/end
|
|
|
|
68/push 0/imm32/start
|
|
|
|
89/<- %edx 4/r32/esp
|
2019-11-30 20:26:30 +00:00
|
|
|
# edi = result
|
2019-11-29 23:23:22 +00:00
|
|
|
(allocate Heap *Stmt-size) # => eax
|
2019-12-22 16:11:34 +00:00
|
|
|
(zero-out %eax *Stmt-size)
|
2019-11-29 23:23:22 +00:00
|
|
|
89/<- %edi 0/r32/eax
|
2019-10-30 00:51:54 +00:00
|
|
|
{ # line loop
|
2019-11-26 05:04:23 +00:00
|
|
|
$parse-mu-block:line-loop:
|
2019-10-30 00:51:54 +00:00
|
|
|
# line = read-line-buffered(in)
|
|
|
|
(clear-stream %ecx)
|
|
|
|
(read-line-buffered *(ebp+8) %ecx)
|
2019-11-29 23:23:22 +00:00
|
|
|
#? (write-buffered Stderr "line: ")
|
|
|
|
#? (write-stream-data Stderr %ecx)
|
|
|
|
#? (write-buffered Stderr Newline)
|
|
|
|
#? (flush Stderr)
|
2019-10-30 00:51:54 +00:00
|
|
|
# if (line->write == 0) break
|
|
|
|
81 7/subop/compare *ecx 0/imm32
|
|
|
|
0f 84/jump-if-equal break/disp32
|
|
|
|
# word-slice = next-word(line)
|
|
|
|
(next-word %ecx %edx)
|
2019-11-29 23:23:22 +00:00
|
|
|
#? (write-buffered Stderr "word: ")
|
|
|
|
#? (write-slice-buffered Stderr %edx)
|
|
|
|
#? (write-buffered Stderr Newline)
|
|
|
|
#? (flush Stderr)
|
2019-11-03 07:43:37 +00:00
|
|
|
# if slice-empty?(word-slice) continue
|
2019-11-30 09:18:41 +00:00
|
|
|
(slice-empty? %edx)
|
2019-10-30 00:51:54 +00:00
|
|
|
3d/compare-eax-and 0/imm32
|
2019-11-29 23:23:22 +00:00
|
|
|
0f 85/jump-if-not-equal loop/disp32
|
2019-10-30 00:51:54 +00:00
|
|
|
# if (slice-starts-with?(word-slice, '#') continue
|
|
|
|
# . eax = *word-slice->start
|
|
|
|
8b/-> *edx 0/r32/eax
|
|
|
|
8a/copy-byte *eax 0/r32/AL
|
|
|
|
81 4/subop/and %eax 0xff/imm32
|
|
|
|
# . if (eax == '#') continue
|
|
|
|
3d/compare-eax-and 0x23/imm32/hash
|
2019-11-29 23:23:22 +00:00
|
|
|
0f 84/jump-if-equal loop/disp32
|
|
|
|
# if slice-equal?(word-slice, "{")
|
2019-10-30 00:51:54 +00:00
|
|
|
{
|
2019-11-29 23:23:22 +00:00
|
|
|
$parse-mu-block:check-for-block:
|
|
|
|
(slice-equal? %edx "{")
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
74/jump-if-equal break/disp8
|
2019-11-29 23:35:28 +00:00
|
|
|
(check-no-tokens-left %ecx)
|
2019-11-29 23:23:22 +00:00
|
|
|
# parse new block and append
|
2019-12-28 06:38:06 +00:00
|
|
|
(parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax
|
2019-11-29 23:23:22 +00:00
|
|
|
(append-to-block %edi %eax)
|
|
|
|
e9/jump $parse-mu-block:line-loop/disp32
|
2019-10-30 00:51:54 +00:00
|
|
|
}
|
2019-11-29 23:23:22 +00:00
|
|
|
# if slice-equal?(word-slice, "}") break
|
|
|
|
$parse-mu-block:check-for-end:
|
|
|
|
(slice-equal? %edx "}")
|
2019-10-30 00:51:54 +00:00
|
|
|
3d/compare-eax-and 0/imm32
|
2019-11-29 23:23:22 +00:00
|
|
|
0f 85/jump-if-not-equal break/disp32
|
|
|
|
# if slice-ends-with?(word-slice, ":") parse named block and append
|
|
|
|
{
|
|
|
|
$parse-mu-block:check-for-named-block:
|
|
|
|
# . eax = *word-slice->end
|
|
|
|
8b/-> *(edx+4) 0/r32/eax
|
|
|
|
8a/copy-byte *eax 0/r32/AL
|
|
|
|
81 4/subop/and %eax 0xff/imm32
|
|
|
|
# . if (eax != ':') break
|
|
|
|
3d/compare-eax-and 0x23/imm32/hash
|
|
|
|
0f 85/jump-if-not-equal break/disp32
|
|
|
|
#
|
2019-12-28 06:38:06 +00:00
|
|
|
(parse-mu-named-block %edx %ecx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax
|
2019-11-29 23:23:22 +00:00
|
|
|
(append-to-block %edi %eax)
|
|
|
|
e9/jump $parse-mu-block:line-loop/disp32
|
|
|
|
}
|
|
|
|
# if slice-equal?(word-slice, "var")
|
|
|
|
{
|
|
|
|
$parse-mu-block:check-for-var:
|
|
|
|
(slice-equal? %edx "var")
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
74/jump-if-equal break/disp8
|
|
|
|
#
|
2019-12-23 07:20:44 +00:00
|
|
|
(parse-mu-var-def %ecx *(ebp+0xc)) # => eax
|
2019-11-29 23:23:22 +00:00
|
|
|
(append-to-block %edi %eax)
|
|
|
|
e9/jump $parse-mu-block:line-loop/disp32
|
|
|
|
}
|
|
|
|
$parse-mu-block:regular-stmt:
|
|
|
|
# otherwise
|
2019-12-28 06:38:06 +00:00
|
|
|
(parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax
|
2019-11-30 20:26:30 +00:00
|
|
|
(append-to-block Heap %edi %eax)
|
2019-11-29 23:23:22 +00:00
|
|
|
e9/jump loop/disp32
|
2019-10-30 00:51:54 +00:00
|
|
|
} # end line loop
|
2019-11-30 20:26:30 +00:00
|
|
|
# return result
|
|
|
|
89/<- %eax 7/r32/edi
|
2019-11-26 05:04:23 +00:00
|
|
|
$parse-mu-block:end:
|
2019-10-30 00:51:54 +00:00
|
|
|
# . reclaim locals
|
|
|
|
81 0/subop/add %esp 0x214/imm32
|
|
|
|
# . restore registers
|
2019-11-29 23:23:22 +00:00
|
|
|
5f/pop-to-edi
|
2019-10-30 00:51:54 +00:00
|
|
|
5b/pop-to-ebx
|
|
|
|
5a/pop-to-edx
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-26 05:04:23 +00:00
|
|
|
$parse-mu-block:abort:
|
2019-10-30 00:51:54 +00:00
|
|
|
# error("'{' or '}' should be on its own line, but got '")
|
|
|
|
(write-buffered Stderr "'{' or '}' should be on its own line, but got '")
|
|
|
|
(rewind-stream %ecx)
|
|
|
|
(write-stream 2 %ecx)
|
|
|
|
(write-buffered Stderr "'\n")
|
|
|
|
(flush Stderr)
|
|
|
|
# . syscall(exit, 1)
|
|
|
|
bb/copy-to-ebx 1/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
# never gets here
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
check-no-tokens-left: # line : (address stream byte)
|
2019-11-29 23:35:28 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
|
|
|
51/push-ecx
|
2019-12-08 21:56:46 +00:00
|
|
|
# var s/ecx : (ref slice)
|
2019-11-29 23:35:28 +00:00
|
|
|
68/push 0/imm32/end
|
|
|
|
68/push 0/imm32/start
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
#
|
|
|
|
(next-word *(ebp+8) %ecx)
|
|
|
|
# if slice-empty?(s) return
|
|
|
|
(slice-empty? %ecx)
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
75/jump-if-not-equal $check-no-tokens-left:end/disp8
|
|
|
|
# if (slice-starts-with?(s, '#') return
|
|
|
|
# . eax = *s->start
|
|
|
|
8b/-> *edx 0/r32/eax
|
|
|
|
8a/copy-byte *eax 0/r32/AL
|
|
|
|
81 4/subop/and %eax 0xff/imm32
|
|
|
|
# . if (eax == '#') continue
|
|
|
|
3d/compare-eax-and 0x23/imm32/hash
|
|
|
|
74/jump-if-equal $check-no-tokens-left:end/disp8
|
|
|
|
# abort
|
|
|
|
(write-buffered Stderr "'{' or '}' should be on its own line, but got '")
|
|
|
|
(rewind-stream %ecx)
|
|
|
|
(write-stream 2 %ecx)
|
|
|
|
(write-buffered Stderr "'\n")
|
|
|
|
(flush Stderr)
|
|
|
|
# . syscall(exit, 1)
|
|
|
|
bb/copy-to-ebx 1/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
# never gets here
|
|
|
|
$check-no-tokens-left:end:
|
|
|
|
# . reclaim locals
|
|
|
|
81 0/subop/add %esp 8/imm32
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-23 07:20:44 +00:00
|
|
|
parse-mu-named-block: # name : (address slice), first-line : (address stream byte), in : (address buffered-file), vars : (address stack (handle var)) -> result/eax : (handle stmt)
|
2019-11-29 23:23:22 +00:00
|
|
|
# pseudocode:
|
2019-12-08 21:56:46 +00:00
|
|
|
# var line : (ref stream byte 512)
|
|
|
|
# var word-slice : (ref slice)
|
2019-11-29 23:23:22 +00:00
|
|
|
# result/eax = allocate(Heap, Stmt-size)
|
|
|
|
# result->tag = 4/Named-block
|
|
|
|
# result->name = name
|
|
|
|
# assert(next-word(first-line) == "{")
|
|
|
|
# assert(no-tokens-in(first-line))
|
|
|
|
# while true # line loop
|
|
|
|
# clear-stream(line)
|
|
|
|
# read-line-buffered(in, line)
|
|
|
|
# if (line->write == 0) break # end of file
|
|
|
|
# word-slice = next-word(line)
|
|
|
|
# if slice-empty?(word-slice) # end of line
|
|
|
|
# break
|
|
|
|
# else if slice-equal?(word-slice, "{")
|
2019-12-23 07:20:44 +00:00
|
|
|
# block = parse-mu-block(in, vars)
|
2019-11-29 23:23:22 +00:00
|
|
|
# append-to-block(result, block)
|
|
|
|
# else if slice-equal?(word-slice, "}")
|
|
|
|
# break
|
|
|
|
# else if slice-ends-with?(word-slice, ":")
|
2019-12-23 07:20:44 +00:00
|
|
|
# named-block = parse-mu-named-block(word-slice, in, vars)
|
2019-11-29 23:23:22 +00:00
|
|
|
# append-to-block(result, named-block)
|
|
|
|
# else if slice-equal?(word-slice, "var")
|
2019-12-23 07:20:44 +00:00
|
|
|
# var-def = parse-mu-var-def(line, vars)
|
2019-11-29 23:23:22 +00:00
|
|
|
# append-to-block(result, var-def)
|
|
|
|
# else
|
2019-12-28 06:38:06 +00:00
|
|
|
# stmt = parse-mu-stmt(line, vars, fn)
|
2019-11-29 23:23:22 +00:00
|
|
|
# append-to-block(result, stmt)
|
|
|
|
# return result
|
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
$parse-mu-named-block:end:
|
|
|
|
# . reclaim locals
|
|
|
|
# . restore registers
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-23 07:20:44 +00:00
|
|
|
parse-mu-var-def: # line : (address stream byte), vars : (address stack (handle var)) -> result/eax : (handle stmt)
|
2019-11-29 23:23:22 +00:00
|
|
|
# pseudocode:
|
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
$parse-mu-var-def:end:
|
|
|
|
# . reclaim locals
|
|
|
|
# . restore registers
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-28 06:38:06 +00:00
|
|
|
parse-mu-stmt: # line : (address stream byte), vars : (address stack (handle var)), fn : (handle function) -> result/eax : (handle stmt)
|
2019-11-29 23:23:22 +00:00
|
|
|
# pseudocode:
|
2019-12-08 21:56:46 +00:00
|
|
|
# var name : (ref slice)
|
2019-11-30 09:18:41 +00:00
|
|
|
# result = allocate(Heap, Stmt-size)
|
|
|
|
# if stmt-has-outputs?(line)
|
|
|
|
# while true
|
|
|
|
# name = next-word(line)
|
|
|
|
# if (name == '<-') break
|
|
|
|
# assert(is-identifier?(name))
|
2019-12-28 06:38:06 +00:00
|
|
|
# var v : (handle var) = lookup-or-define-var(name, vars)
|
2019-11-30 09:18:41 +00:00
|
|
|
# result->outputs = append(result->outputs, v)
|
|
|
|
# result->name = slice-to-string(next-word(line))
|
|
|
|
# while true
|
|
|
|
# name = next-word-or-string(line)
|
2019-12-28 06:38:06 +00:00
|
|
|
# v = lookup-var-or-literal(name)
|
2019-11-30 09:18:41 +00:00
|
|
|
# result->inouts = append(result->inouts, v)
|
2019-11-29 23:23:22 +00:00
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
2019-11-30 09:18:41 +00:00
|
|
|
51/push-ecx
|
|
|
|
57/push-edi
|
2019-12-08 21:56:46 +00:00
|
|
|
# var name/ecx : (ref slice)
|
2019-11-30 09:18:41 +00:00
|
|
|
68/push 0/imm32/end
|
|
|
|
68/push 0/imm32/start
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# result/edi : (handle stmt)
|
2019-12-22 16:11:34 +00:00
|
|
|
(allocate Heap *Stmt-size) # => eax
|
|
|
|
(zero-out %eax *Stmt-size)
|
2019-11-30 09:18:41 +00:00
|
|
|
89/<- %edi 0/r32/eax
|
2019-11-30 22:16:05 +00:00
|
|
|
# result->tag = 1/stmt
|
|
|
|
c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag
|
2019-11-30 09:18:41 +00:00
|
|
|
{
|
|
|
|
(stmt-has-outputs? *(ebp+8))
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
0f 84/jump-if-equal break/disp32
|
|
|
|
{
|
|
|
|
$parse-mu-stmt:read-outputs:
|
|
|
|
# name = next-word(line)
|
|
|
|
(next-word *(ebp+8) %ecx)
|
|
|
|
# if slice-empty?(word-slice) break
|
|
|
|
(slice-empty? %ecx)
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
0f 85/jump-if-not-equal break/disp32
|
|
|
|
# if (name == "<-") break
|
|
|
|
(slice-equal? %ecx "<-")
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
# assert(is-identifier?(name))
|
|
|
|
(is-identifier? %ecx)
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
0f 84/jump-if-equal $parse-mu-stmt:abort/disp32
|
|
|
|
#
|
2019-12-28 06:38:06 +00:00
|
|
|
(lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax
|
2019-11-30 09:18:41 +00:00
|
|
|
(append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax
|
|
|
|
89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs
|
|
|
|
e9/jump loop/disp32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$parse-mu-stmt:read-operation:
|
|
|
|
(next-word *(ebp+8) %ecx)
|
|
|
|
(slice-to-string Heap %ecx)
|
|
|
|
89/<- *(edi+4) 0/r32/eax # Stmt1-operation
|
|
|
|
{
|
|
|
|
$parse-mu-stmt:read-inouts:
|
|
|
|
# name = next-word-or-string(line)
|
|
|
|
(next-word-or-string *(ebp+8) %ecx)
|
|
|
|
# if slice-empty?(word-slice) break
|
|
|
|
(slice-empty? %ecx)
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
0f 85/jump-if-not-equal break/disp32
|
|
|
|
# if (name == "<-") abort
|
|
|
|
(slice-equal? %ecx "<-")
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
0f 85/jump-if-not-equal $parse-mu-stmt:abort2/disp32
|
|
|
|
#
|
2019-12-28 06:38:06 +00:00
|
|
|
(lookup-var %ecx *(ebp+0xc)) # => eax # TODO: lookup-var-or-literal
|
2019-11-30 09:18:41 +00:00
|
|
|
(append-list Heap %eax *(edi+8)) # Stmt1-inouts => eax
|
|
|
|
89/<- *(edi+8) 0/r32/eax # Stmt1-inouts
|
|
|
|
e9/jump loop/disp32
|
|
|
|
}
|
2019-11-29 23:23:22 +00:00
|
|
|
$parse-mu-stmt:end:
|
2019-11-30 09:18:41 +00:00
|
|
|
# return result
|
|
|
|
89/<- %eax 7/r32/edi
|
2019-11-29 23:23:22 +00:00
|
|
|
# . reclaim locals
|
2019-11-30 09:18:41 +00:00
|
|
|
81 0/subop/add %esp 8/imm32
|
2019-11-29 23:23:22 +00:00
|
|
|
# . restore registers
|
2019-11-30 09:18:41 +00:00
|
|
|
5f/pop-to-edi
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
$parse-mu-stmt:abort:
|
|
|
|
# error("invalid identifier '" name "'\n")
|
|
|
|
(write-buffered Stderr "invalid identifier '")
|
|
|
|
(write-slice-buffered Stderr %ecx)
|
|
|
|
(write-buffered Stderr "'\n")
|
|
|
|
(flush Stderr)
|
|
|
|
# . syscall(exit, 1)
|
|
|
|
bb/copy-to-ebx 1/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
# never gets here
|
|
|
|
|
|
|
|
$parse-mu-stmt:abort2:
|
|
|
|
# error("invalid statement '" line "'\n")
|
|
|
|
(rewind-stream *(ebp+8))
|
|
|
|
(write-buffered Stderr "invalid identifier '")
|
|
|
|
(write-stream Stderr *(ebp+8))
|
|
|
|
(write-buffered Stderr "'\n")
|
|
|
|
(flush Stderr)
|
|
|
|
# . syscall(exit, 1)
|
|
|
|
bb/copy-to-ebx 1/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
# never gets here
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
stmt-has-outputs?: # line : (address stream byte) -> result/eax : boolean
|
2019-11-30 09:18:41 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
2019-12-08 21:56:46 +00:00
|
|
|
# var word-slice/ecx : (ref slice)
|
2019-11-30 09:18:41 +00:00
|
|
|
68/push 0/imm32/end
|
|
|
|
68/push 0/imm32/start
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
# result = false
|
|
|
|
b8/copy-to-eax 0/imm32/false
|
|
|
|
(rewind-stream *(ebp+8))
|
|
|
|
{
|
|
|
|
(next-word-or-string *(ebp+8) %ecx)
|
|
|
|
# if slice-empty?(word-slice) break
|
|
|
|
(slice-empty? %ecx)
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false)
|
|
|
|
0f 85/jump-if-not-equal break/disp32
|
|
|
|
# if slice-starts-with?(word-slice, '#') break
|
|
|
|
# . eax = *word-slice->start
|
|
|
|
8b/-> *ecx 0/r32/eax
|
|
|
|
8a/copy-byte *eax 0/r32/AL
|
|
|
|
81 4/subop/and %eax 0xff/imm32
|
|
|
|
# . if (eax == '#') break
|
|
|
|
3d/compare-eax-and 0x23/imm32/hash
|
|
|
|
b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false)
|
|
|
|
0f 84/jump-if-equal break/disp32
|
|
|
|
# if slice-equal?(word-slice, '<-') return true
|
|
|
|
(slice-equal? %ecx "<-")
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
74/jump-if-equal loop/disp8
|
|
|
|
b8/copy-to-eax 1/imm32/true
|
|
|
|
}
|
|
|
|
$stmt-has-outputs:end:
|
|
|
|
(rewind-stream *(ebp+8))
|
|
|
|
# . reclaim locals
|
|
|
|
81 0/subop/add %esp 8/imm32
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-23 07:20:44 +00:00
|
|
|
lookup-var: # name: (address slice), vars : (address stack (handle var)) -> result/eax: (handle var)
|
2019-12-28 03:10:34 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# var target/eax : (handle array byte) = slice-to-string(name)
|
|
|
|
(slice-to-string Heap *(ebp+8)) # => eax
|
|
|
|
#
|
|
|
|
(lookup-var-helper %eax *(ebp+0xc)) # => eax
|
|
|
|
# if (result == 0) abort
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
74/jump-if-equal $lookup-var:abort/disp8
|
|
|
|
$lookup-var:end:
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
$lookup-var:abort:
|
|
|
|
(write-buffered Stderr "unknown variable '")
|
|
|
|
(write-slice-buffered Stderr *(ebp+8))
|
|
|
|
(write-buffered Stderr "'\n")
|
|
|
|
(flush Stderr)
|
|
|
|
# . syscall(exit, 1)
|
|
|
|
bb/copy-to-ebx 1/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
# never gets here
|
|
|
|
|
|
|
|
lookup-var-helper: # name: (address array byte), vars : (address stack (handle var)) -> result/eax: (handle var)
|
2019-12-23 07:20:44 +00:00
|
|
|
# pseudocode:
|
|
|
|
# var curr : (address handle var) = &vars->data[vars->top - 4]
|
|
|
|
# var min = vars->data
|
|
|
|
# while curr >= min
|
|
|
|
# var v : (handle var) = *curr
|
|
|
|
# if v->name == name
|
|
|
|
# return v
|
2019-12-28 03:10:34 +00:00
|
|
|
# return 0
|
2019-12-23 07:20:44 +00:00
|
|
|
#
|
2019-11-30 09:18:41 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
2019-12-23 07:20:44 +00:00
|
|
|
52/push-edx
|
|
|
|
53/push-ebx
|
|
|
|
56/push-esi
|
|
|
|
# esi = vars
|
|
|
|
8b/-> *(ebp+0xc) 6/r32/esi
|
|
|
|
# ebx = vars->top
|
|
|
|
8b/-> *esi 3/r32/ebx
|
|
|
|
# if (vars->top > vars->length) abort
|
|
|
|
3b/compare 0/r32/eax *(esi+4)
|
2019-12-28 03:10:34 +00:00
|
|
|
0f 8f/jump-if-greater $lookup-var-helper:error1/disp32
|
2019-12-23 07:20:44 +00:00
|
|
|
# var min/edx : (address handle var) = vars->data
|
|
|
|
8d/copy-address *(esi+8) 2/r32/edx
|
|
|
|
# var curr/ebx : (address handle var) = &vars->data[vars->top - 4]
|
|
|
|
81 5/subop/subtract %ebx 4/imm32
|
|
|
|
8d/copy-address *(esi+ebx+8) 3/r32/ebx
|
|
|
|
{
|
2019-12-28 03:10:34 +00:00
|
|
|
# if (curr < min) return 0
|
2019-12-23 07:20:44 +00:00
|
|
|
39/compare %ebx 2/r32/edx
|
2019-12-28 03:10:34 +00:00
|
|
|
b8/copy-to-eax 0/imm32
|
|
|
|
0f 82/jump-if-lesser-unsigned break/disp32
|
2019-12-23 07:20:44 +00:00
|
|
|
# var v/eax : (handle var) = *curr
|
|
|
|
8b/-> *ebx 0/r32/eax
|
2019-12-28 03:10:34 +00:00
|
|
|
# if (v->name == name) return v
|
|
|
|
(string-equal? *eax *(ebp+8)) # Var-name
|
2019-12-23 07:20:44 +00:00
|
|
|
3d/compare-eax-and 0/imm32
|
2019-12-28 03:10:34 +00:00
|
|
|
8b/-> *ebx 0/r32/eax
|
2019-12-23 07:20:44 +00:00
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
8b/-> *(ebx+4) 3/r32/ebx # List-next
|
|
|
|
e9/jump loop/disp32
|
|
|
|
}
|
2019-12-28 03:10:34 +00:00
|
|
|
$lookup-var-helper:end:
|
2019-11-30 09:18:41 +00:00
|
|
|
# . restore registers
|
2019-12-23 07:20:44 +00:00
|
|
|
5e/pop-to-esi
|
|
|
|
5b/pop-to-ebx
|
|
|
|
5a/pop-to-edx
|
2019-11-30 09:18:41 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-28 03:10:34 +00:00
|
|
|
$lookup-var-helper:error1:
|
2019-12-23 07:20:44 +00:00
|
|
|
(write-buffered Stderr "malformed stack when looking up '")
|
|
|
|
(write-slice-buffered Stderr *(ebp+8))
|
|
|
|
(write-buffered Stderr "'\n")
|
|
|
|
(flush Stderr)
|
|
|
|
# . syscall(exit, 1)
|
|
|
|
bb/copy-to-ebx 1/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
# never gets here
|
|
|
|
|
2019-12-28 06:38:06 +00:00
|
|
|
lookup-or-define-var: # name: (address slice), vars : (address stack (handle var)), fn : (handle function) -> result/eax: (handle var)
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
# var target/ecx : (handle array byte) = slice-to-string(name)
|
|
|
|
(slice-to-string Heap *(ebp+8)) # => eax
|
|
|
|
89/<- %ecx 0/r32/eax
|
|
|
|
#
|
|
|
|
(lookup-var-helper *(ebp+8) *(ebp+0xc)) # => eax
|
|
|
|
{
|
|
|
|
# if (result != 0) return
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
# if name is one of fn's outputs, return it
|
|
|
|
{
|
|
|
|
(find-in-function-outputs *(ebp+0x10) %ecx) # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
# otherwise abort
|
|
|
|
0f 84/jump-if-not-equal $lookup-var:abort/disp32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$lookup-or-define-var:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
find-in-function-outputs: # fn : (handle function), name : (handle array byte) => result/eax : (handle var)
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
# var curr/ecx : (handle list var) = fn->outputs
|
|
|
|
8b/-> *(ebp+8) 1/r32/ecx
|
|
|
|
8b/-> *(ecx+0xc) 1/r32/ecx
|
|
|
|
# while curr != null
|
|
|
|
{
|
|
|
|
81 7/subop/compare %ecx 0/imm32
|
|
|
|
74/jump-if-equal break/disp8
|
|
|
|
# var v : (handle var) = *curr
|
|
|
|
8b/-> *ecx 0/r32/eax # List-value
|
|
|
|
# if (curr->name == name) return curr
|
|
|
|
50/push-eax
|
|
|
|
(string-equal? *eax *(ebp+0xc))
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
58/pop-to-eax
|
|
|
|
75/jump-if-not-equal $find-in-function-outputs:end/disp8
|
|
|
|
# curr = curr->next
|
|
|
|
8b/-> *(ecx+4) 1/r32/ecx # List-next
|
|
|
|
eb/jump loop/disp8
|
|
|
|
}
|
|
|
|
b8/copy-to-eax 0/imm32
|
|
|
|
$find-in-function-outputs:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-30 09:18:41 +00:00
|
|
|
test-parse-mu-stmt:
|
|
|
|
# 'increment n'
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-input-stream)
|
|
|
|
(write _test-input-stream "increment n\n")
|
2019-12-23 07:20:44 +00:00
|
|
|
# var vars/ecx : (ref stack (address var) 4)
|
|
|
|
81 5/subop/subtract %esp 0x10/imm32
|
|
|
|
68/push 0x10/imm32/length
|
|
|
|
68/push 0/imm32/top
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
(clear-stack %ecx)
|
|
|
|
# var v/edx : (ref var)
|
|
|
|
81 5/subop/subtract %esp 0x14/imm32 # Var-size
|
|
|
|
89/<- %edx 4/r32/esp
|
|
|
|
(zero-out %edx 0x14)
|
|
|
|
# v->name = "n"
|
|
|
|
c7 0/subop/copy *edx "n"/imm32 # Var-name
|
|
|
|
#
|
|
|
|
(push %ecx %edx)
|
2019-11-30 09:18:41 +00:00
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(parse-mu-stmt _test-input-stream %ecx)
|
2019-11-30 09:18:41 +00:00
|
|
|
# check result
|
|
|
|
(check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation
|
2019-12-08 21:56:46 +00:00
|
|
|
# edx : (handle list var) = result->inouts
|
2019-11-30 09:18:41 +00:00
|
|
|
8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts
|
2019-12-08 21:56:46 +00:00
|
|
|
# ebx : (handle var) = result->inouts->value
|
2019-11-30 09:18:41 +00:00
|
|
|
8b/-> *edx 3/r32/ebx # List-value
|
|
|
|
(check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name
|
2019-11-29 23:23:22 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
new-function: # ad: allocation-descriptor, name: string, subx-name: string, inouts: (handle list var), outputs: (handle list var), body: (handle block), next: (handle function) -> result/eax: (handle function)
|
2019-11-28 00:50:23 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
#
|
|
|
|
(allocate *(ebp+8) *Function-size) # => eax
|
|
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
|
|
89/<- *eax 1/r32/ecx # Function-name
|
|
|
|
8b/-> *(ebp+0x10) 1/r32/ecx
|
|
|
|
89/<- *(eax+4) 1/r32/ecx # Function-subx-name
|
|
|
|
8b/-> *(ebp+0x14) 1/r32/ecx
|
|
|
|
89/<- *(eax+8) 1/r32/ecx # Function-inouts
|
|
|
|
8b/-> *(ebp+0x18) 1/r32/ecx
|
|
|
|
89/<- *(eax+0xc) 1/r32/ecx # Function-outputs
|
|
|
|
8b/-> *(ebp+0x1c) 1/r32/ecx
|
|
|
|
89/<- *(eax+0x10) 1/r32/ecx # Function-body
|
|
|
|
8b/-> *(ebp+0x20) 1/r32/ecx
|
|
|
|
89/<- *(eax+0x14) 1/r32/ecx # Function-next
|
|
|
|
$new-function:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
new-var: # ad: allocation-descriptor, name: string, type: int, block: int, stack-offset: int, register: string -> result/eax: (handle var)
|
2019-11-28 00:50:23 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
#
|
|
|
|
(allocate *(ebp+8) *Var-size) # => eax
|
|
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
|
|
89/<- *eax 1/r32/ecx # Var-name
|
|
|
|
8b/-> *(ebp+0x10) 1/r32/ecx
|
|
|
|
89/<- *(eax+4) 1/r32/ecx # Var-type
|
|
|
|
8b/-> *(ebp+0x14) 1/r32/ecx
|
|
|
|
89/<- *(eax+8) 1/r32/ecx # Var-block
|
|
|
|
8b/-> *(ebp+0x18) 1/r32/ecx
|
|
|
|
89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset
|
|
|
|
8b/-> *(ebp+0x1c) 1/r32/ecx
|
|
|
|
89/<- *(eax+0x10) 1/r32/ecx # Var-register
|
|
|
|
$new-var:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
new-block: # ad: allocation-descriptor, data: (handle list statement) -> result/eax: (handle statement)
|
2019-11-28 00:50:23 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
#
|
|
|
|
(allocate *(ebp+8) *Stmt-size) # => eax
|
2019-12-22 16:11:34 +00:00
|
|
|
(zero-out %eax *Stmt-size)
|
2019-11-28 00:50:23 +00:00
|
|
|
c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag
|
|
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
|
|
89/<- *(eax+4) 1/r32/ecx # Block-statements
|
|
|
|
$new-block:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
new-stmt: # ad: allocation-descriptor, operation: string, inouts: (handle list var), outputs: (handle list var) -> result/eax: (handle statement)
|
2019-11-28 00:50:23 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
#
|
|
|
|
(allocate *(ebp+8) *Stmt-size) # => eax
|
2019-12-22 16:11:34 +00:00
|
|
|
(zero-out %eax *Stmt-size)
|
2019-11-28 00:50:23 +00:00
|
|
|
c7 0/subop/copy *eax 1/imm32/tag/regular-stmt # Stmt-tag
|
|
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
|
|
89/<- *(eax+4) 1/r32/ecx # Stmt1-operation
|
|
|
|
8b/-> *(ebp+0x10) 1/r32/ecx
|
|
|
|
89/<- *(eax+8) 1/r32/ecx # Stmt1-inouts
|
|
|
|
8b/-> *(ebp+0x14) 1/r32/ecx
|
|
|
|
89/<- *(eax+0xc) 1/r32/ecx # Stmt1-outputs
|
|
|
|
$new-stmt:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
new-vardef: # ad: allocation-descriptor, name: string, type: int -> result/eax: (handle statement)
|
2019-11-28 00:50:23 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
#
|
|
|
|
(allocate *(ebp+8) *Stmt-size) # => eax
|
2019-12-22 16:11:34 +00:00
|
|
|
(zero-out %eax *Stmt-size)
|
2019-11-28 00:50:23 +00:00
|
|
|
c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag
|
|
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
|
|
89/<- *(eax+4) 1/r32/ecx # Vardef-name
|
|
|
|
8b/-> *(ebp+0x10) 1/r32/ecx
|
|
|
|
89/<- *(eax+8) 1/r32/ecx # Vardef-type
|
|
|
|
$new-vardef:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
new-regvardef: # ad: allocation-descriptor, name: string, type: int, register: string -> result/eax: (handle statement)
|
2019-11-28 00:50:23 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
#
|
|
|
|
(allocate *(ebp+8) *Stmt-size) # => eax
|
2019-12-22 16:11:34 +00:00
|
|
|
(zero-out %eax *Stmt-size)
|
2019-11-28 00:50:23 +00:00
|
|
|
c7 0/subop/copy *eax 3/imm32/tag/var-in-register
|
|
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
|
|
89/<- *(eax+4) 1/r32/ecx # Regvardef-name
|
|
|
|
8b/-> *(ebp+0x10) 1/r32/ecx
|
|
|
|
89/<- *(eax+8) 1/r32/ecx # Regvardef-type
|
|
|
|
8b/-> *(ebp+0x14) 1/r32/ecx
|
|
|
|
89/<- *(eax+0xc) 1/r32/ecx # Regvardef-register
|
|
|
|
$new-regvardef:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
new-named-block: # ad: allocation-descriptor, name: string, data: (handle list statement) -> result/eax: (handle statement)
|
2019-11-28 00:50:23 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
#
|
|
|
|
(allocate *(ebp+8) *Stmt-size) # => eax
|
2019-12-22 16:11:34 +00:00
|
|
|
(zero-out %eax *Stmt-size)
|
2019-11-28 00:50:23 +00:00
|
|
|
c7 0/subop/copy *eax 4/imm32/tag/named-block
|
|
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
|
|
89/<- *(eax+4) 1/r32/ecx # Named-block-name
|
|
|
|
8b/-> *(ebp+0x10) 1/r32/ecx
|
|
|
|
89/<- *(eax+8) 1/r32/ecx # Named-block-statements
|
|
|
|
$new-named-block:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
new-list: # ad: allocation-descriptor, value: _type, next: (handle list _type) -> result/eax : (handle list _type)
|
2019-11-29 08:09:06 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
#
|
|
|
|
(allocate *(ebp+8) *List-size) # => eax
|
|
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
|
|
89/<- *eax 1/r32/ecx # List-value
|
|
|
|
8b/-> *(ebp+0x10) 1/r32/ecx
|
|
|
|
89/<- *(eax+4) 1/r32/ecx # List-next
|
|
|
|
$new-list:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
append-list: # ad: allocation-descriptor, value: _type, list: (handle list _type) -> result/eax : (handle list _type)
|
2019-11-29 09:24:03 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
#
|
|
|
|
(allocate *(ebp+8) *List-size) # => eax
|
|
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
|
|
89/<- *eax 1/r32/ecx # List-value
|
|
|
|
# if (list == null) return result
|
|
|
|
81 7/subop/compare *(ebp+0x10) 0/imm32
|
|
|
|
74/jump-if-equal $new-list:end/disp8
|
|
|
|
# otherwise append
|
|
|
|
# var curr/ecx = list
|
|
|
|
8b/-> *(ebp+0x10) 1/r32/ecx
|
|
|
|
# while (curr->next != null) curr = curr->next
|
|
|
|
{
|
|
|
|
81 7/subop/compare *(ecx+4) 0/imm32 # List-next
|
|
|
|
74/jump-if-equal break/disp8
|
|
|
|
# curr = curr->next
|
|
|
|
8b/-> *(ecx+4) 1/r32/ecx
|
|
|
|
eb/jump loop/disp8
|
|
|
|
}
|
|
|
|
# curr->next = result
|
|
|
|
89/<- *(ecx+4) 0/r32/eax
|
|
|
|
# return list
|
|
|
|
8b/-> *(ebp+0x10) 0/r32/eax
|
|
|
|
$append-list:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
append-to-block: # ad: allocation-descriptor, block: (handle block), x: (handle stmt)
|
2019-11-29 23:23:22 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
2019-11-30 20:26:30 +00:00
|
|
|
56/push-esi
|
|
|
|
# esi = block
|
|
|
|
8b/-> *(ebp+0xc) 6/r32/esi
|
|
|
|
(append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements
|
|
|
|
89/<- *(esi+4) 0/r32/eax # Block-statements
|
2019-11-29 23:23:22 +00:00
|
|
|
$append-to-block:end:
|
|
|
|
# . restore registers
|
2019-11-30 20:26:30 +00:00
|
|
|
5e/pop-to-esi
|
2019-11-29 23:23:22 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-28 00:50:23 +00:00
|
|
|
#######################################################
|
|
|
|
# Type-checking
|
|
|
|
#######################################################
|
|
|
|
|
2019-10-30 00:51:54 +00:00
|
|
|
check-mu-types:
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
#
|
2019-11-28 00:50:23 +00:00
|
|
|
$check-mu-types:end:
|
2019-10-30 00:51:54 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-22 16:11:34 +00:00
|
|
|
size-of: # n : (address var)
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# hard-coded since we only support 'int' types for now
|
|
|
|
b8/copy-to-eax 4/imm32
|
|
|
|
$size-of:end:
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-28 00:50:23 +00:00
|
|
|
#######################################################
|
|
|
|
# Code-generation
|
|
|
|
#######################################################
|
|
|
|
|
2019-10-30 00:51:54 +00:00
|
|
|
emit-subx: # out : (address buffered-file)
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
|
|
|
51/push-ecx
|
|
|
|
57/push-edi
|
|
|
|
# edi = out
|
|
|
|
8b/-> *(ebp+8) 7/r32/edi
|
2019-12-08 21:56:46 +00:00
|
|
|
# var curr/ecx : (handle function) = Program
|
2019-10-30 00:51:54 +00:00
|
|
|
8b/-> *Program 1/r32/ecx
|
|
|
|
{
|
2019-12-08 21:56:46 +00:00
|
|
|
# if (curr == null) break
|
2019-10-30 00:51:54 +00:00
|
|
|
81 7/subop/compare %ecx 0/imm32
|
|
|
|
0f 84/jump-if-equal break/disp32
|
2019-11-09 01:31:11 +00:00
|
|
|
(emit-subx-function %edi %ecx)
|
2019-10-30 00:51:54 +00:00
|
|
|
# curr = curr->next
|
2019-11-26 05:04:23 +00:00
|
|
|
8b/-> *(ecx+0x14) 1/r32/ecx # Function-next
|
2019-10-30 00:51:54 +00:00
|
|
|
e9/jump loop/disp32
|
|
|
|
}
|
|
|
|
$emit-subx:end:
|
|
|
|
# . restore registers
|
|
|
|
5f/pop-to-edi
|
|
|
|
59/pop-to-ecx
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
emit-subx-function: # out : (address buffered-file), f : (handle function)
|
2019-11-09 01:31:11 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
|
|
|
51/push-ecx
|
|
|
|
57/push-edi
|
|
|
|
# edi = out
|
|
|
|
8b/-> *(ebp+8) 7/r32/edi
|
|
|
|
# ecx = f
|
|
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
|
|
#
|
|
|
|
(write-buffered %edi *ecx)
|
|
|
|
(write-buffered %edi ":\n")
|
|
|
|
(emit-subx-prologue %edi)
|
2019-11-15 01:29:40 +00:00
|
|
|
(emit-subx-block %edi *(ecx+0x10)) # Function-body
|
2019-11-09 01:31:11 +00:00
|
|
|
(emit-subx-epilogue %edi)
|
|
|
|
$emit-subx-function:end:
|
|
|
|
# . restore registers
|
|
|
|
5f/pop-to-edi
|
|
|
|
59/pop-to-ecx
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
emit-subx-block: # out : (address buffered-file), block : (handle block)
|
2019-11-09 01:31:11 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# curr/esi : (handle list statement) = block->statements
|
2019-11-30 20:26:30 +00:00
|
|
|
8b/-> *(ebp+0xc) 6/r32/esi
|
|
|
|
8b/-> *(esi+4) 6/r32/esi # Block-statements
|
2019-11-09 01:31:11 +00:00
|
|
|
#
|
2019-11-30 20:26:30 +00:00
|
|
|
{
|
2019-12-22 16:11:34 +00:00
|
|
|
$emit-subx-block:check-empty:
|
2019-11-30 20:26:30 +00:00
|
|
|
81 7/subop/compare %esi 0/imm32
|
2019-11-30 22:16:05 +00:00
|
|
|
0f 84/jump-if-equal break/disp32
|
2019-11-30 20:26:30 +00:00
|
|
|
(write-buffered *(ebp+8) "{\n")
|
2019-11-30 22:16:05 +00:00
|
|
|
{
|
2019-12-22 16:11:34 +00:00
|
|
|
$emit-subx-block:stmt:
|
2019-11-30 22:16:05 +00:00
|
|
|
81 7/subop/compare %esi 0/imm32
|
|
|
|
74/jump-if-equal break/disp8
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-statement *(ebp+8) *esi Primitives 0)
|
2019-11-30 22:16:05 +00:00
|
|
|
(write-buffered *(ebp+8) Newline)
|
|
|
|
8b/-> *(esi+4) 6/r32/esi # List-next
|
|
|
|
eb/jump loop/disp8
|
|
|
|
}
|
2019-11-30 20:26:30 +00:00
|
|
|
(write-buffered *(ebp+8) "}\n")
|
|
|
|
}
|
2019-11-09 01:31:11 +00:00
|
|
|
$emit-subx-block:end:
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-23 07:20:44 +00:00
|
|
|
emit-subx-statement: # out : (address buffered-file), stmt : (handle statement), primitives : (handle primitive), functions : (handle function)
|
2019-11-09 01:31:11 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
2019-11-09 17:00:42 +00:00
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
|
|
|
51/push-ecx
|
2019-11-09 20:52:54 +00:00
|
|
|
# if stmt matches a primitive, emit it
|
2019-11-09 01:31:11 +00:00
|
|
|
{
|
2019-11-16 02:41:45 +00:00
|
|
|
$emit-subx-statement:primitive:
|
2019-12-23 07:20:44 +00:00
|
|
|
(find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax
|
2019-11-09 17:00:42 +00:00
|
|
|
3d/compare-eax-and 0/imm32
|
2019-11-09 20:52:54 +00:00
|
|
|
74/jump-if-equal break/disp8
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr
|
2019-11-09 20:52:54 +00:00
|
|
|
e9/jump $emit-subx-statement:end/disp32
|
|
|
|
}
|
|
|
|
# else if stmt matches a function, emit a call to it
|
|
|
|
{
|
2019-11-16 02:41:45 +00:00
|
|
|
$emit-subx-statement:call:
|
2019-12-23 07:20:44 +00:00
|
|
|
(find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax
|
2019-11-09 20:09:20 +00:00
|
|
|
3d/compare-eax-and 0/imm32
|
2019-11-09 20:52:54 +00:00
|
|
|
74/jump-if-equal break/disp8
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr
|
2019-11-09 20:52:54 +00:00
|
|
|
e9/jump $emit-subx-statement:end/disp32
|
2019-11-09 01:31:11 +00:00
|
|
|
}
|
2019-11-09 20:52:54 +00:00
|
|
|
# else abort
|
|
|
|
e9/jump $emit-subx-statement:abort/disp32
|
2019-11-09 01:31:11 +00:00
|
|
|
$emit-subx-statement:end:
|
2019-11-09 17:00:42 +00:00
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
$emit-subx-statement:abort:
|
|
|
|
# error("couldn't translate '" stmt "'\n")
|
|
|
|
(write-buffered Stderr "couldn't translate '")
|
|
|
|
#? (emit-string Stderr *(ebp+0xc)) # TODO
|
|
|
|
(write-buffered Stderr "'\n")
|
|
|
|
(flush Stderr)
|
|
|
|
# . syscall(exit, 1)
|
|
|
|
bb/copy-to-ebx 1/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
# never gets here
|
|
|
|
|
2019-11-18 08:24:24 +00:00
|
|
|
# Primitives supported
|
2019-12-26 08:28:16 +00:00
|
|
|
# For each operation, put variants with hard-coded registers before flexible ones.
|
2019-11-18 08:24:24 +00:00
|
|
|
== data
|
|
|
|
Primitives:
|
2019-12-26 08:28:16 +00:00
|
|
|
# - increment/decrement
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-inc-eax:
|
2019-12-26 09:49:41 +00:00
|
|
|
# var/eax <- increment => 40/increment-eax
|
2019-12-26 08:11:25 +00:00
|
|
|
"increment"/imm32/name
|
|
|
|
0/imm32/no-inouts
|
|
|
|
Single-int-var-in-eax/imm32/outputs
|
|
|
|
"40/increment-eax"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-inc-ecx/imm32/next
|
|
|
|
_Primitive-inc-ecx:
|
2019-12-26 09:49:41 +00:00
|
|
|
# var/ecx <- increment => 41/increment-ecx
|
2019-12-26 08:11:25 +00:00
|
|
|
"increment"/imm32/name
|
|
|
|
0/imm32/no-inouts
|
|
|
|
Single-int-var-in-ecx/imm32/outputs
|
|
|
|
"41/increment-ecx"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-inc-edx/imm32/next
|
|
|
|
_Primitive-inc-edx:
|
2019-12-26 09:49:41 +00:00
|
|
|
# var/edx <- increment => 42/increment-edx
|
2019-12-26 08:11:25 +00:00
|
|
|
"increment"/imm32/name
|
|
|
|
0/imm32/no-inouts
|
|
|
|
Single-int-var-in-edx/imm32/outputs
|
|
|
|
"42/increment-edx"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-inc-ebx/imm32/next
|
|
|
|
_Primitive-inc-ebx:
|
2019-12-26 09:49:41 +00:00
|
|
|
# var/ebx <- increment => 43/increment-ebx
|
2019-12-26 08:11:25 +00:00
|
|
|
"increment"/imm32/name
|
|
|
|
0/imm32/no-inouts
|
|
|
|
Single-int-var-in-ebx/imm32/outputs
|
|
|
|
"43/increment-ebx"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-inc-esi/imm32/next
|
|
|
|
_Primitive-inc-esi:
|
2019-12-26 09:49:41 +00:00
|
|
|
# var/esi <- increment => 46/increment-esi
|
2019-12-26 08:11:25 +00:00
|
|
|
"increment"/imm32/name
|
|
|
|
0/imm32/no-inouts
|
|
|
|
Single-int-var-in-esi/imm32/outputs
|
|
|
|
"46/increment-esi"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-inc-edi/imm32/next
|
|
|
|
_Primitive-inc-edi:
|
2019-12-26 09:49:41 +00:00
|
|
|
# var/edi <- increment => 47/increment-edi
|
2019-12-26 08:11:25 +00:00
|
|
|
"increment"/imm32/name
|
|
|
|
0/imm32/no-inouts
|
|
|
|
Single-int-var-in-edi/imm32/outputs
|
|
|
|
"47/increment-edi"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-dec-eax/imm32/next
|
|
|
|
_Primitive-dec-eax:
|
2019-12-26 09:49:41 +00:00
|
|
|
# var/eax <- decrement => 48/decrement-eax
|
2019-12-26 08:11:25 +00:00
|
|
|
"decrement"/imm32/name
|
|
|
|
0/imm32/no-inouts
|
|
|
|
Single-int-var-in-eax/imm32/outputs
|
|
|
|
"48/decrement-eax"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-dec-ecx/imm32/next
|
|
|
|
_Primitive-dec-ecx:
|
2019-12-26 09:49:41 +00:00
|
|
|
# var/ecx <- decrement => 49/decrement-ecx
|
2019-12-26 08:11:25 +00:00
|
|
|
"decrement"/imm32/name
|
|
|
|
0/imm32/no-inouts
|
|
|
|
Single-int-var-in-ecx/imm32/outputs
|
|
|
|
"49/decrement-ecx"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-dec-edx/imm32/next
|
|
|
|
_Primitive-dec-edx:
|
2019-12-26 09:49:41 +00:00
|
|
|
# var/edx <- decrement => 4a/decrement-edx
|
2019-12-26 08:11:25 +00:00
|
|
|
"decrement"/imm32/name
|
|
|
|
0/imm32/no-inouts
|
|
|
|
Single-int-var-in-edx/imm32/outputs
|
|
|
|
"4a/decrement-edx"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-dec-ebx/imm32/next
|
|
|
|
_Primitive-dec-ebx:
|
2019-12-26 09:49:41 +00:00
|
|
|
# var/ebx <- decrement => 4b/decrement-ebx
|
2019-12-26 08:11:25 +00:00
|
|
|
"decrement"/imm32/name
|
|
|
|
0/imm32/no-inouts
|
|
|
|
Single-int-var-in-ebx/imm32/outputs
|
|
|
|
"4b/decrement-ebx"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-dec-esi/imm32/next
|
|
|
|
_Primitive-dec-esi:
|
2019-12-26 09:49:41 +00:00
|
|
|
# var/esi <- decrement => 4e/decrement-esi
|
2019-12-26 08:11:25 +00:00
|
|
|
"decrement"/imm32/name
|
|
|
|
0/imm32/no-inouts
|
|
|
|
Single-int-var-in-esi/imm32/outputs
|
|
|
|
"4e/decrement-esi"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-dec-edi/imm32/next
|
|
|
|
_Primitive-dec-edi:
|
2019-12-26 09:49:41 +00:00
|
|
|
# var/edi <- decrement => 4f/decrement-edi
|
2019-12-26 08:11:25 +00:00
|
|
|
"decrement"/imm32/name
|
|
|
|
0/imm32/no-inouts
|
|
|
|
Single-int-var-in-edi/imm32/outputs
|
|
|
|
"4f/decrement-edi"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-inc-mem/imm32/next
|
|
|
|
_Primitive-inc-mem:
|
2019-11-18 08:24:24 +00:00
|
|
|
# increment var => ff 0/subop/increment *(ebp+__)
|
|
|
|
"increment"/imm32/name
|
|
|
|
Single-int-var-on-stack/imm32/inouts
|
|
|
|
0/imm32/no-outputs
|
|
|
|
"ff 0/subop/increment"/imm32/subx-name
|
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-11-18 09:13:31 +00:00
|
|
|
_Primitive-inc-reg/imm32/next
|
2019-11-18 08:24:24 +00:00
|
|
|
_Primitive-inc-reg:
|
|
|
|
# var/reg <- increment => ff 0/subop/increment %__
|
|
|
|
"increment"/imm32/name
|
|
|
|
0/imm32/no-inouts
|
2019-11-18 09:13:31 +00:00
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
2019-11-18 08:24:24 +00:00
|
|
|
"ff 0/subop/increment"/imm32/subx-name
|
|
|
|
3/imm32/rm32-is-first-output
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-dec-mem/imm32/next
|
|
|
|
_Primitive-dec-mem:
|
|
|
|
# decrement var => ff 1/subop/decrement *(ebp+__)
|
|
|
|
"decrement"/imm32/name
|
|
|
|
Single-int-var-on-stack/imm32/inouts
|
|
|
|
0/imm32/no-outputs
|
|
|
|
"ff 1/subop/decrement"/imm32/subx-name
|
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:11:25 +00:00
|
|
|
_Primitive-dec-reg/imm32/next
|
|
|
|
_Primitive-dec-reg:
|
|
|
|
# var/reg <- decrement => ff 1/subop/decrement %__
|
|
|
|
"decrement"/imm32/name
|
|
|
|
0/imm32/no-inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
|
|
|
"ff 1/subop/decrement"/imm32/subx-name
|
|
|
|
3/imm32/rm32-is-first-output
|
|
|
|
0/imm32/no-r32
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:28:16 +00:00
|
|
|
_Primitive-add-to-eax/imm32/next
|
|
|
|
# - add
|
|
|
|
_Primitive-add-to-eax:
|
2019-12-26 09:49:41 +00:00
|
|
|
# var/eax <- add lit => 05/add-to-eax lit/imm32
|
2019-12-26 08:28:16 +00:00
|
|
|
"add"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-eax/imm32/outputs
|
|
|
|
"05/add-to-eax"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-11-18 09:13:31 +00:00
|
|
|
_Primitive-add-reg-to-reg/imm32/next
|
|
|
|
_Primitive-add-reg-to-reg:
|
2019-12-26 10:21:55 +00:00
|
|
|
# var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
|
2019-11-18 09:13:31 +00:00
|
|
|
"add"/imm32/name
|
|
|
|
Single-int-var-in-some-register/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
2019-12-26 10:21:55 +00:00
|
|
|
"01/add-to"/imm32/subx-name
|
2019-11-18 09:13:31 +00:00
|
|
|
3/imm32/rm32-is-first-output
|
|
|
|
1/imm32/r32-is-first-inout
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-11-27 01:41:25 +00:00
|
|
|
_Primitive-add-reg-to-mem/imm32/next
|
|
|
|
_Primitive-add-reg-to-mem:
|
2019-12-26 10:21:55 +00:00
|
|
|
# add-to var1 var2/reg => 01/add-to var1 var2/r32
|
2019-11-27 01:41:25 +00:00
|
|
|
"add-to"/imm32/name
|
|
|
|
Int-var-and-second-int-var-in-some-register/imm32/inouts
|
|
|
|
0/imm32/outputs
|
2019-12-26 10:21:55 +00:00
|
|
|
"01/add-to"/imm32/subx-name
|
2019-11-27 01:41:25 +00:00
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
2/imm32/r32-is-second-inout
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-11-27 01:41:25 +00:00
|
|
|
_Primitive-add-mem-to-reg/imm32/next
|
|
|
|
_Primitive-add-mem-to-reg:
|
2019-12-26 08:28:16 +00:00
|
|
|
# var1/reg <- add var2 => 03/add var2/rm32 var1/r32
|
2019-11-27 01:41:25 +00:00
|
|
|
"add"/imm32/name
|
|
|
|
Single-int-var-on-stack/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
2019-12-26 08:28:16 +00:00
|
|
|
"03/add"/imm32/subx-name
|
2019-11-27 01:41:25 +00:00
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
3/imm32/r32-is-first-output
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-11-19 00:30:30 +00:00
|
|
|
_Primitive-add-lit-to-reg/imm32/next
|
|
|
|
_Primitive-add-lit-to-reg:
|
|
|
|
# var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
|
|
|
|
"add"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
|
|
|
"81 0/subop/add"/imm32/subx-name
|
|
|
|
3/imm32/rm32-is-first-output
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-11-27 01:41:25 +00:00
|
|
|
_Primitive-add-lit-to-mem/imm32/next
|
|
|
|
_Primitive-add-lit-to-mem:
|
|
|
|
# add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
|
2019-11-27 02:07:55 +00:00
|
|
|
"add-to"/imm32/name
|
2019-11-27 01:41:25 +00:00
|
|
|
Int-var-and-literal/imm32/inouts
|
|
|
|
0/imm32/outputs
|
|
|
|
"81 0/subop/add"/imm32/subx-name
|
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
0/imm32/no-r32
|
|
|
|
2/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:28:16 +00:00
|
|
|
_Primitive-subtract-from-eax/imm32/next
|
|
|
|
# - subtract
|
|
|
|
_Primitive-subtract-from-eax:
|
2019-12-26 09:49:41 +00:00
|
|
|
# var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
|
2019-12-26 08:28:16 +00:00
|
|
|
"subtract"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-eax/imm32/outputs
|
|
|
|
"2d/subtract-from-eax"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:28:16 +00:00
|
|
|
_Primitive-subtract-reg-from-reg/imm32/next
|
|
|
|
_Primitive-subtract-reg-from-reg:
|
2019-12-26 10:21:55 +00:00
|
|
|
# var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
|
2019-12-26 08:28:16 +00:00
|
|
|
"subtract"/imm32/name
|
|
|
|
Single-int-var-in-some-register/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
2019-12-26 10:21:55 +00:00
|
|
|
"29/subtract-from"/imm32/subx-name
|
2019-12-26 08:28:16 +00:00
|
|
|
3/imm32/rm32-is-first-output
|
|
|
|
1/imm32/r32-is-first-inout
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:28:16 +00:00
|
|
|
_Primitive-subtract-reg-from-mem/imm32/next
|
|
|
|
_Primitive-subtract-reg-from-mem:
|
2019-12-26 10:21:55 +00:00
|
|
|
# subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
|
2019-12-26 08:28:16 +00:00
|
|
|
"subtract-from"/imm32/name
|
|
|
|
Int-var-and-second-int-var-in-some-register/imm32/inouts
|
|
|
|
0/imm32/outputs
|
2019-12-26 10:21:55 +00:00
|
|
|
"29/subtract-from"/imm32/subx-name
|
2019-12-26 08:28:16 +00:00
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
2/imm32/r32-is-second-inout
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:28:16 +00:00
|
|
|
_Primitive-subtract-mem-from-reg/imm32/next
|
|
|
|
_Primitive-subtract-mem-from-reg:
|
|
|
|
# var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
|
|
|
|
"subtract"/imm32/name
|
|
|
|
Single-int-var-on-stack/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
|
|
|
"2b/subtract"/imm32/subx-name
|
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
3/imm32/r32-is-first-output
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:28:16 +00:00
|
|
|
_Primitive-subtract-lit-from-reg/imm32/next
|
|
|
|
_Primitive-subtract-lit-from-reg:
|
|
|
|
# var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
|
|
|
|
"subtract"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
|
|
|
"81 5/subop/subtract"/imm32/subx-name
|
|
|
|
3/imm32/rm32-is-first-output
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 08:28:16 +00:00
|
|
|
_Primitive-subtract-lit-from-mem/imm32/next
|
|
|
|
_Primitive-subtract-lit-from-mem:
|
|
|
|
# subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
|
|
|
|
"subtract-from"/imm32/name
|
|
|
|
Int-var-and-literal/imm32/inouts
|
|
|
|
0/imm32/outputs
|
|
|
|
"81 5/subop/subtract"/imm32/subx-name
|
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
0/imm32/no-r32
|
|
|
|
2/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-and-with-eax/imm32/next
|
|
|
|
# - and
|
|
|
|
_Primitive-and-with-eax:
|
|
|
|
# var/eax <- and lit => 25/and-with-eax lit/imm32
|
|
|
|
"and"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-eax/imm32/outputs
|
|
|
|
"25/and-with-eax"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-and-reg-with-reg/imm32/next
|
|
|
|
_Primitive-and-reg-with-reg:
|
2019-12-26 10:21:55 +00:00
|
|
|
# var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
|
2019-12-26 09:49:41 +00:00
|
|
|
"and"/imm32/name
|
|
|
|
Single-int-var-in-some-register/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
2019-12-26 10:21:55 +00:00
|
|
|
"21/and-with"/imm32/subx-name
|
2019-12-26 09:49:41 +00:00
|
|
|
3/imm32/rm32-is-first-output
|
|
|
|
1/imm32/r32-is-first-inout
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-and-reg-with-mem/imm32/next
|
|
|
|
_Primitive-and-reg-with-mem:
|
2019-12-26 10:21:55 +00:00
|
|
|
# and-with var1 var2/reg => 21/and-with var1 var2/r32
|
2019-12-26 09:49:41 +00:00
|
|
|
"and-with"/imm32/name
|
|
|
|
Int-var-and-second-int-var-in-some-register/imm32/inouts
|
|
|
|
0/imm32/outputs
|
2019-12-26 10:21:55 +00:00
|
|
|
"21/and-with"/imm32/subx-name
|
2019-12-26 09:49:41 +00:00
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
2/imm32/r32-is-second-inout
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-and-mem-with-reg/imm32/next
|
|
|
|
_Primitive-and-mem-with-reg:
|
|
|
|
# var1/reg <- and var2 => 23/and var2/rm32 var1/r32
|
|
|
|
"and"/imm32/name
|
|
|
|
Single-int-var-on-stack/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
|
|
|
"23/and"/imm32/subx-name
|
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
3/imm32/r32-is-first-output
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-and-lit-with-reg/imm32/next
|
|
|
|
_Primitive-and-lit-with-reg:
|
|
|
|
# var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
|
|
|
|
"and"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
|
|
|
"81 4/subop/and"/imm32/subx-name
|
|
|
|
3/imm32/rm32-is-first-output
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-and-lit-with-mem/imm32/next
|
|
|
|
_Primitive-and-lit-with-mem:
|
|
|
|
# and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
|
|
|
|
"and-with"/imm32/name
|
|
|
|
Int-var-and-literal/imm32/inouts
|
|
|
|
0/imm32/outputs
|
|
|
|
"81 4/subop/and"/imm32/subx-name
|
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
0/imm32/no-r32
|
|
|
|
2/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-or-with-eax/imm32/next
|
|
|
|
# - or
|
|
|
|
_Primitive-or-with-eax:
|
|
|
|
# var/eax <- or lit => 0d/or-with-eax lit/imm32
|
|
|
|
"or"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-eax/imm32/outputs
|
|
|
|
"0d/or-with-eax"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-or-reg-with-reg/imm32/next
|
|
|
|
_Primitive-or-reg-with-reg:
|
2019-12-26 10:21:55 +00:00
|
|
|
# var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
|
2019-12-26 09:49:41 +00:00
|
|
|
"or"/imm32/name
|
|
|
|
Single-int-var-in-some-register/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
2019-12-26 10:21:55 +00:00
|
|
|
"09/or-with"/imm32/subx-name
|
2019-12-26 09:49:41 +00:00
|
|
|
3/imm32/rm32-is-first-output
|
|
|
|
1/imm32/r32-is-first-inout
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-or-reg-with-mem/imm32/next
|
|
|
|
_Primitive-or-reg-with-mem:
|
2019-12-26 10:21:55 +00:00
|
|
|
# or-with var1 var2/reg => 09/or-with var1 var2/r32
|
2019-12-26 09:49:41 +00:00
|
|
|
"or-with"/imm32/name
|
|
|
|
Int-var-and-second-int-var-in-some-register/imm32/inouts
|
|
|
|
0/imm32/outputs
|
2019-12-26 10:21:55 +00:00
|
|
|
"09/or-with"/imm32/subx-name
|
2019-12-26 09:49:41 +00:00
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
2/imm32/r32-is-second-inout
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-or-mem-with-reg/imm32/next
|
|
|
|
_Primitive-or-mem-with-reg:
|
|
|
|
# var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
|
|
|
|
"or"/imm32/name
|
|
|
|
Single-int-var-on-stack/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
|
|
|
"0b/or"/imm32/subx-name
|
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
3/imm32/r32-is-first-output
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-or-lit-with-reg/imm32/next
|
|
|
|
_Primitive-or-lit-with-reg:
|
|
|
|
# var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
|
|
|
|
"or"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
|
|
|
"81 4/subop/or"/imm32/subx-name
|
|
|
|
3/imm32/rm32-is-first-output
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-or-lit-with-mem/imm32/next
|
|
|
|
_Primitive-or-lit-with-mem:
|
|
|
|
# or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
|
|
|
|
"or-with"/imm32/name
|
|
|
|
Int-var-and-literal/imm32/inouts
|
|
|
|
0/imm32/outputs
|
|
|
|
"81 4/subop/or"/imm32/subx-name
|
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
0/imm32/no-r32
|
|
|
|
2/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-xor-with-eax/imm32/next
|
|
|
|
# - xor
|
|
|
|
_Primitive-xor-with-eax:
|
|
|
|
# var/eax <- xor lit => 35/xor-with-eax lit/imm32
|
|
|
|
"xor"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-eax/imm32/outputs
|
|
|
|
"35/xor-with-eax"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-xor-reg-with-reg/imm32/next
|
|
|
|
_Primitive-xor-reg-with-reg:
|
2019-12-26 10:21:55 +00:00
|
|
|
# var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
|
2019-12-26 09:49:41 +00:00
|
|
|
"xor"/imm32/name
|
|
|
|
Single-int-var-in-some-register/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
2019-12-26 10:21:55 +00:00
|
|
|
"31/xor-with"/imm32/subx-name
|
2019-12-26 09:49:41 +00:00
|
|
|
3/imm32/rm32-is-first-output
|
|
|
|
1/imm32/r32-is-first-inout
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-xor-reg-with-mem/imm32/next
|
|
|
|
_Primitive-xor-reg-with-mem:
|
2019-12-26 10:21:55 +00:00
|
|
|
# xor-with var1 var2/reg => 31/xor-with var1 var2/r32
|
2019-12-26 09:49:41 +00:00
|
|
|
"xor-with"/imm32/name
|
|
|
|
Int-var-and-second-int-var-in-some-register/imm32/inouts
|
|
|
|
0/imm32/outputs
|
2019-12-26 10:21:55 +00:00
|
|
|
"31/xor-with"/imm32/subx-name
|
2019-12-26 09:49:41 +00:00
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
2/imm32/r32-is-second-inout
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-xor-mem-with-reg/imm32/next
|
|
|
|
_Primitive-xor-mem-with-reg:
|
|
|
|
# var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
|
|
|
|
"xor"/imm32/name
|
|
|
|
Single-int-var-on-stack/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
|
|
|
"33/xor"/imm32/subx-name
|
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
3/imm32/r32-is-first-output
|
|
|
|
0/imm32/no-imm32
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-xor-lit-with-reg/imm32/next
|
|
|
|
_Primitive-xor-lit-with-reg:
|
|
|
|
# var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
|
|
|
|
"xor"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
|
|
|
"81 4/subop/xor"/imm32/subx-name
|
|
|
|
3/imm32/rm32-is-first-output
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 09:49:41 +00:00
|
|
|
_Primitive-xor-lit-with-mem/imm32/next
|
|
|
|
_Primitive-xor-lit-with-mem:
|
|
|
|
# xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
|
|
|
|
"xor-with"/imm32/name
|
|
|
|
Int-var-and-literal/imm32/inouts
|
|
|
|
0/imm32/outputs
|
|
|
|
"81 4/subop/xor"/imm32/subx-name
|
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
0/imm32/no-r32
|
|
|
|
2/imm32/imm32-is-first-inout
|
2019-12-26 10:02:57 +00:00
|
|
|
0/imm32/output-is-write-only
|
2019-12-26 10:21:55 +00:00
|
|
|
_Primitive-copy-to-eax/imm32/next
|
|
|
|
# - copy
|
|
|
|
_Primitive-copy-to-eax:
|
|
|
|
# var/eax <- copy lit => b8/copy-to-eax lit/imm32
|
|
|
|
"copy"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-eax/imm32/outputs
|
|
|
|
"b8/copy-to-eax"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
|
|
|
1/imm32/output-is-write-only
|
|
|
|
_Primitive-copy-to-ecx/imm32/next
|
|
|
|
_Primitive-copy-to-ecx:
|
|
|
|
# var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
|
|
|
|
"copy"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-ecx/imm32/outputs
|
|
|
|
"b9/copy-to-ecx"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
|
|
|
1/imm32/output-is-write-only
|
|
|
|
_Primitive-copy-to-edx/imm32/next
|
|
|
|
_Primitive-copy-to-edx:
|
|
|
|
# var/edx <- copy lit => ba/copy-to-edx lit/imm32
|
|
|
|
"copy"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-edx/imm32/outputs
|
|
|
|
"ba/copy-to-edx"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
|
|
|
1/imm32/output-is-write-only
|
|
|
|
_Primitive-copy-to-ebx/imm32/next
|
|
|
|
_Primitive-copy-to-ebx:
|
|
|
|
# var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
|
|
|
|
"copy"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-ebx/imm32/outputs
|
|
|
|
"bb/copy-to-ebx"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
|
|
|
1/imm32/output-is-write-only
|
|
|
|
_Primitive-copy-to-esi/imm32/next
|
|
|
|
_Primitive-copy-to-esi:
|
|
|
|
# var/esi <- copy lit => be/copy-to-esi lit/imm32
|
|
|
|
"copy"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-esi/imm32/outputs
|
|
|
|
"be/copy-to-esi"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
|
|
|
1/imm32/output-is-write-only
|
|
|
|
_Primitive-copy-to-edi/imm32/next
|
|
|
|
_Primitive-copy-to-edi:
|
|
|
|
# var/edi <- copy lit => bf/copy-to-edi lit/imm32
|
|
|
|
"copy"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-edi/imm32/outputs
|
|
|
|
"bf/copy-to-edi"/imm32/subx-name
|
|
|
|
0/imm32/no-rm32
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
|
|
|
1/imm32/output-is-write-only
|
|
|
|
_Primitive-copy-reg-to-reg/imm32/next
|
|
|
|
_Primitive-copy-reg-to-reg:
|
|
|
|
# var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32
|
|
|
|
"copy"/imm32/name
|
|
|
|
Single-int-var-in-some-register/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
|
|
|
"89/copy-to"/imm32/subx-name
|
|
|
|
3/imm32/rm32-is-first-output
|
|
|
|
1/imm32/r32-is-first-inout
|
|
|
|
0/imm32/no-imm32
|
|
|
|
1/imm32/output-is-write-only
|
|
|
|
_Primitive-copy-reg-to-mem/imm32/next
|
|
|
|
_Primitive-copy-reg-to-mem:
|
|
|
|
# copy-to var1 var2/reg => 89/copy-to var1 var2/r32
|
|
|
|
"copy-to"/imm32/name
|
|
|
|
Int-var-and-second-int-var-in-some-register/imm32/inouts
|
|
|
|
0/imm32/outputs
|
|
|
|
"89/copy-to"/imm32/subx-name
|
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
2/imm32/r32-is-second-inout
|
|
|
|
0/imm32/no-imm32
|
|
|
|
1/imm32/output-is-write-only
|
|
|
|
_Primitive-copy-mem-to-reg/imm32/next
|
|
|
|
_Primitive-copy-mem-to-reg:
|
|
|
|
# var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32
|
|
|
|
"copy"/imm32/name
|
|
|
|
Single-int-var-on-stack/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
|
|
|
"8b/copy-from"/imm32/subx-name
|
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
3/imm32/r32-is-first-output
|
|
|
|
0/imm32/no-imm32
|
|
|
|
1/imm32/output-is-write-only
|
|
|
|
_Primitive-copy-lit-to-reg/imm32/next
|
|
|
|
_Primitive-copy-lit-to-reg:
|
|
|
|
# var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
|
|
|
|
"copy"/imm32/name
|
|
|
|
Single-lit-var/imm32/inouts
|
|
|
|
Single-int-var-in-some-register/imm32/outputs
|
|
|
|
"c7 0/subop/copy"/imm32/subx-name
|
|
|
|
3/imm32/rm32-is-first-output
|
|
|
|
0/imm32/no-r32
|
|
|
|
1/imm32/imm32-is-first-inout
|
|
|
|
1/imm32/output-is-write-only
|
|
|
|
_Primitive-copy-lit-to-mem/imm32/next
|
|
|
|
_Primitive-copy-lit-to-mem:
|
|
|
|
# copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
|
|
|
|
"copy-to"/imm32/name
|
|
|
|
Int-var-and-literal/imm32/inouts
|
|
|
|
0/imm32/outputs
|
|
|
|
"c7 0/subop/copy"/imm32/subx-name
|
|
|
|
1/imm32/rm32-is-first-inout
|
|
|
|
0/imm32/no-r32
|
|
|
|
2/imm32/imm32-is-first-inout
|
|
|
|
1/imm32/output-is-write-only
|
2019-11-18 08:24:24 +00:00
|
|
|
0/imm32/next
|
|
|
|
|
|
|
|
Single-int-var-on-stack:
|
|
|
|
Int-var-on-stack/imm32
|
|
|
|
0/imm32/next
|
|
|
|
|
|
|
|
Int-var-on-stack:
|
|
|
|
"arg1"/imm32/name
|
|
|
|
1/imm32/type-int
|
|
|
|
1/imm32/some-block-depth
|
|
|
|
1/imm32/some-stack-offset
|
|
|
|
0/imm32/no-register
|
|
|
|
|
2019-11-27 01:41:25 +00:00
|
|
|
Int-var-and-second-int-var-in-some-register:
|
|
|
|
Int-var-on-stack/imm32
|
2019-11-27 02:07:55 +00:00
|
|
|
Single-int-var-in-some-register/imm32/next
|
2019-11-27 01:41:25 +00:00
|
|
|
|
|
|
|
Int-var-and-literal:
|
|
|
|
Int-var-on-stack/imm32
|
|
|
|
Single-lit-var/imm32/next
|
|
|
|
|
2019-11-18 09:13:31 +00:00
|
|
|
Single-int-var-in-some-register:
|
2019-11-18 08:24:24 +00:00
|
|
|
Int-var-in-some-register/imm32
|
|
|
|
0/imm32/next
|
|
|
|
|
|
|
|
Int-var-in-some-register:
|
|
|
|
"arg1"/imm32/name
|
|
|
|
1/imm32/type-int
|
|
|
|
1/imm32/some-block-depth
|
2019-11-27 01:41:25 +00:00
|
|
|
0/imm32/no-stack-offset
|
2019-11-18 08:24:24 +00:00
|
|
|
"*"/imm32/register
|
|
|
|
|
2019-12-26 08:11:25 +00:00
|
|
|
Single-int-var-in-eax:
|
|
|
|
Int-var-in-eax/imm32
|
|
|
|
0/imm32/next
|
|
|
|
|
|
|
|
Int-var-in-eax:
|
|
|
|
"arg1"/imm32/name
|
|
|
|
1/imm32/type-int
|
|
|
|
1/imm32/some-block-depth
|
|
|
|
0/imm32/no-stack-offset
|
|
|
|
"eax"/imm32/register
|
|
|
|
|
|
|
|
Single-int-var-in-ecx:
|
|
|
|
Int-var-in-ecx/imm32
|
|
|
|
0/imm32/next
|
|
|
|
|
|
|
|
Int-var-in-ecx:
|
|
|
|
"arg1"/imm32/name
|
|
|
|
1/imm32/type-int
|
|
|
|
1/imm32/some-block-depth
|
|
|
|
0/imm32/no-stack-offset
|
|
|
|
"ecx"/imm32/register
|
|
|
|
|
|
|
|
Single-int-var-in-edx:
|
|
|
|
Int-var-in-edx/imm32
|
|
|
|
0/imm32/next
|
|
|
|
|
|
|
|
Int-var-in-edx:
|
|
|
|
"arg1"/imm32/name
|
|
|
|
1/imm32/type-int
|
|
|
|
1/imm32/some-block-depth
|
|
|
|
0/imm32/no-stack-offset
|
|
|
|
"edx"/imm32/register
|
|
|
|
|
|
|
|
Single-int-var-in-ebx:
|
|
|
|
Int-var-in-ebx/imm32
|
|
|
|
0/imm32/next
|
|
|
|
|
|
|
|
Int-var-in-ebx:
|
|
|
|
"arg1"/imm32/name
|
|
|
|
1/imm32/type-int
|
|
|
|
1/imm32/some-block-depth
|
|
|
|
0/imm32/no-stack-offset
|
|
|
|
"ebx"/imm32/register
|
|
|
|
|
|
|
|
Single-int-var-in-esi:
|
|
|
|
Int-var-in-esi/imm32
|
|
|
|
0/imm32/next
|
|
|
|
|
|
|
|
Int-var-in-esi:
|
|
|
|
"arg1"/imm32/name
|
|
|
|
1/imm32/type-int
|
|
|
|
1/imm32/some-block-depth
|
|
|
|
0/imm32/no-stack-offset
|
|
|
|
"esi"/imm32/register
|
|
|
|
|
|
|
|
Single-int-var-in-edi:
|
|
|
|
Int-var-in-edi/imm32
|
|
|
|
0/imm32/next
|
|
|
|
|
|
|
|
Int-var-in-edi:
|
|
|
|
"arg1"/imm32/name
|
|
|
|
1/imm32/type-int
|
|
|
|
1/imm32/some-block-depth
|
|
|
|
0/imm32/no-stack-offset
|
|
|
|
"edi"/imm32/register
|
|
|
|
|
2019-11-19 00:30:30 +00:00
|
|
|
Single-lit-var:
|
|
|
|
Lit-var/imm32
|
|
|
|
0/imm32/next
|
|
|
|
|
|
|
|
Lit-var:
|
|
|
|
"literal"/imm32/name
|
|
|
|
0/imm32/type-literal
|
|
|
|
1/imm32/some-block-depth
|
|
|
|
0/imm32/no-stack-offset
|
|
|
|
0/imm32/no-register
|
|
|
|
|
2019-11-18 08:24:24 +00:00
|
|
|
== code
|
2019-12-23 07:20:44 +00:00
|
|
|
emit-subx-primitive: # out : (address buffered-file), stmt : (handle statement), primitive : (handle function)
|
2019-11-09 20:52:54 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
|
|
|
51/push-ecx
|
2019-11-16 02:41:45 +00:00
|
|
|
# ecx = primitive
|
2019-12-23 07:20:44 +00:00
|
|
|
8b/-> *(ebp+0x10) 1/r32/ecx
|
2019-11-16 02:41:45 +00:00
|
|
|
# emit primitive name
|
|
|
|
(write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name
|
|
|
|
# emit rm32 if necessary
|
|
|
|
(emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt
|
2019-11-18 09:13:31 +00:00
|
|
|
# emit r32 if necessary
|
|
|
|
(emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt
|
2019-11-19 00:30:30 +00:00
|
|
|
# emit imm32 if necessary
|
|
|
|
(emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt
|
2019-11-16 02:41:45 +00:00
|
|
|
$emit-subx-primitive:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
emit-subx-rm32: # out : (address buffered-file), l : arg-location, stmt : (handle statement)
|
2019-11-16 02:41:45 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
|
|
|
# if (l == 0) return
|
|
|
|
81 7/subop/compare *(ebp+0xc) 0/imm32
|
|
|
|
74/jump-if-equal $emit-subx-rm32:end/disp8
|
|
|
|
#
|
|
|
|
(get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax
|
2019-11-19 01:36:59 +00:00
|
|
|
(emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var
|
2019-11-16 02:41:45 +00:00
|
|
|
$emit-subx-rm32:end:
|
|
|
|
# . restore registers
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
get-stmt-operand-from-arg-location: # stmt : (handle statement), l : arg-location -> var/eax : (handle variable)
|
2019-11-16 02:41:45 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
# eax = l
|
|
|
|
8b/-> *(ebp+0xc) 0/r32/eax
|
|
|
|
# ecx = stmt
|
|
|
|
8b/-> *(ebp+8) 1/r32/ecx
|
|
|
|
# if (l == 1) return stmt->inouts->var
|
2019-11-11 05:03:33 +00:00
|
|
|
{
|
2019-11-16 02:41:45 +00:00
|
|
|
3d/compare-eax-and 1/imm32
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
$get-stmt-operand-from-arg-location:1:
|
2019-11-26 05:00:07 +00:00
|
|
|
8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts
|
2019-11-16 02:41:45 +00:00
|
|
|
8b/-> *eax 0/r32/eax # Operand-var
|
|
|
|
eb/jump $get-stmt-operand-from-arg-location:end/disp8
|
2019-11-11 05:03:33 +00:00
|
|
|
}
|
2019-11-16 02:41:45 +00:00
|
|
|
# if (l == 2) return stmt->inouts->next->var
|
|
|
|
{
|
|
|
|
3d/compare-eax-and 2/imm32
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
$get-stmt-operand-from-arg-location:2:
|
2019-11-26 05:00:07 +00:00
|
|
|
8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts
|
2019-11-16 02:41:45 +00:00
|
|
|
8b/-> *(eax+4) 0/r32/eax # Operand-next
|
|
|
|
8b/-> *eax 0/r32/eax # Operand-var
|
|
|
|
eb/jump $get-stmt-operand-from-arg-location:end/disp8
|
|
|
|
}
|
|
|
|
# if (l == 3) return stmt->outputs
|
|
|
|
{
|
|
|
|
3d/compare-eax-and 3/imm32
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
$get-stmt-operand-from-arg-location:3:
|
2019-11-26 05:00:07 +00:00
|
|
|
8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs
|
2019-11-16 02:41:45 +00:00
|
|
|
8b/-> *eax 0/r32/eax # Operand-var
|
|
|
|
eb/jump $get-stmt-operand-from-arg-location:end/disp8
|
|
|
|
}
|
|
|
|
# abort
|
|
|
|
e9/jump $get-stmt-operand-from-arg-location:abort/disp32
|
|
|
|
$get-stmt-operand-from-arg-location:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
$get-stmt-operand-from-arg-location:abort:
|
|
|
|
# error("invalid arg-location " eax)
|
|
|
|
(write-buffered Stderr "invalid arg-location ")
|
|
|
|
(print-int32-buffered Stderr %eax)
|
|
|
|
(write-buffered Stderr "\n")
|
|
|
|
(flush Stderr)
|
|
|
|
# . syscall(exit, 1)
|
|
|
|
bb/copy-to-ebx 1/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/exit
|
|
|
|
cd/syscall 0x80/imm8
|
|
|
|
# never gets here
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
emit-subx-r32: # out : (address buffered-file), l : arg-location, stmt : (handle statement)
|
2019-11-16 02:41:45 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
|
|
|
51/push-ecx
|
|
|
|
# if (location == 0) return
|
2019-11-18 09:13:31 +00:00
|
|
|
81 7/subop/compare *(ebp+0xc) 0/imm32
|
|
|
|
0f 84/jump-if-equal $emit-subx-r32:end/disp32
|
|
|
|
#
|
|
|
|
(get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax
|
|
|
|
(maybe-get Registers *(eax+0x10) 8) # Var-register => eax : (address register-index)
|
|
|
|
(write-buffered *(ebp+8) Space)
|
|
|
|
(print-int32-buffered *(ebp+8) *eax)
|
|
|
|
(write-buffered *(ebp+8) "/r32")
|
2019-11-16 02:41:45 +00:00
|
|
|
$emit-subx-r32:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
emit-subx-imm32: # out : (address buffered-file), l : arg-location, stmt : (handle statement)
|
2019-11-16 02:41:45 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
|
|
|
51/push-ecx
|
2019-11-18 09:13:31 +00:00
|
|
|
# if (location == 0) return
|
|
|
|
81 7/subop/compare *(ebp+0xc) 0/imm32
|
|
|
|
74/jump-if-equal $emit-subx-imm32:end/disp8
|
|
|
|
#
|
|
|
|
(get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax
|
2019-11-19 00:30:30 +00:00
|
|
|
(write-buffered *(ebp+8) Space)
|
|
|
|
(write-buffered *(ebp+8) *eax) # Var-name
|
|
|
|
(write-buffered *(ebp+8) "/imm32")
|
2019-11-16 02:41:45 +00:00
|
|
|
$emit-subx-imm32:end:
|
2019-11-09 20:52:54 +00:00
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-23 07:20:44 +00:00
|
|
|
emit-subx-call: # out : (address buffered-file), stmt : (handle statement), callee : (handle function)
|
2019-11-09 20:52:54 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
|
|
|
51/push-ecx
|
2019-11-10 03:04:48 +00:00
|
|
|
#
|
|
|
|
(write-buffered *(ebp+8) "(")
|
2019-11-11 05:03:33 +00:00
|
|
|
# - emit function name
|
2019-12-23 07:20:44 +00:00
|
|
|
8b/-> *(ebp+0x10) 1/r32/ecx
|
2019-11-11 03:09:38 +00:00
|
|
|
(write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name
|
2019-11-11 05:03:33 +00:00
|
|
|
# - emit arguments
|
2019-12-08 21:56:46 +00:00
|
|
|
# var curr/ecx : (handle list var) = stmt->inouts
|
2019-11-11 05:03:33 +00:00
|
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
2019-11-26 05:00:07 +00:00
|
|
|
8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts
|
2019-11-11 05:03:33 +00:00
|
|
|
{
|
|
|
|
# if (curr == null) break
|
|
|
|
81 7/subop/compare %ecx 0/imm32
|
|
|
|
74/jump-if-equal break/disp8
|
|
|
|
#
|
|
|
|
(emit-subx-call-operand *(ebp+8) *ecx)
|
|
|
|
# curr = curr->next
|
|
|
|
8b/-> *(ecx+4) 1/r32/ecx
|
|
|
|
}
|
2019-11-10 03:04:48 +00:00
|
|
|
#
|
|
|
|
(write-buffered *(ebp+8) ")")
|
2019-11-09 20:52:54 +00:00
|
|
|
$emit-subx-call:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
emit-subx-call-operand: # out : (address buffered-file), operand : (handle variable)
|
2019-11-19 01:36:59 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
|
|
|
# eax = operand
|
|
|
|
8b/-> *(ebp+0xc) 0/r32/eax
|
|
|
|
# if non-literal, emit appropriately
|
|
|
|
(emit-subx-var-as-rm32 *(ebp+8) %eax)
|
|
|
|
# else if (operand->type == literal) emit "__"
|
|
|
|
{
|
|
|
|
81 7/subop/compare *(eax+4) 0/imm32 # Var-type
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
$emit-subx-call-operand:literal:
|
|
|
|
(write-buffered *(ebp+8) Space)
|
|
|
|
(write-buffered *(ebp+8) *eax)
|
|
|
|
}
|
|
|
|
$emit-subx-call-operand:end:
|
|
|
|
# . restore registers
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
emit-subx-var-as-rm32: # out : (address buffered-file), operand : (handle variable)
|
2019-11-11 05:03:33 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
50/push-eax
|
2019-11-16 02:41:45 +00:00
|
|
|
# eax = operand
|
2019-11-11 05:03:33 +00:00
|
|
|
8b/-> *(ebp+0xc) 0/r32/eax
|
2019-11-16 02:41:45 +00:00
|
|
|
# if (operand->register) emit "%__"
|
|
|
|
{
|
|
|
|
81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register
|
|
|
|
74/jump-if-equal break/disp8
|
2019-11-19 01:36:59 +00:00
|
|
|
$emit-subx-var-as-rm32:register:
|
2019-11-16 02:41:45 +00:00
|
|
|
(write-buffered *(ebp+8) " %")
|
|
|
|
(write-buffered *(ebp+8) *(eax+0x10)) # Var-register
|
|
|
|
}
|
|
|
|
# else if (operand->stack-offset) emit "*(ebp+__)"
|
|
|
|
{
|
|
|
|
81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset
|
|
|
|
74/jump-if-equal break/disp8
|
2019-11-19 01:36:59 +00:00
|
|
|
$emit-subx-var-as-rm32:stack:
|
2019-11-16 02:41:45 +00:00
|
|
|
(write-buffered *(ebp+8) Space)
|
|
|
|
(write-buffered *(ebp+8) "*(ebp+")
|
|
|
|
8b/-> *(ebp+0xc) 0/r32/eax
|
|
|
|
(print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset
|
|
|
|
(write-buffered *(ebp+8) ")")
|
|
|
|
}
|
2019-11-19 01:36:59 +00:00
|
|
|
$emit-subx-var-as-rm32:end:
|
2019-11-11 05:03:33 +00:00
|
|
|
# . restore registers
|
|
|
|
58/pop-to-eax
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
find-matching-function: # functions : (address function), stmt : (handle statement) -> result/eax : (handle function)
|
2019-11-09 20:09:20 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
2019-12-08 21:56:46 +00:00
|
|
|
# var curr/ecx : (handle function) = functions
|
2019-11-10 03:04:48 +00:00
|
|
|
8b/-> *(ebp+8) 1/r32/ecx
|
2019-11-09 20:09:20 +00:00
|
|
|
{
|
|
|
|
# if (curr == null) break
|
|
|
|
81 7/subop/compare %ecx 0/imm32
|
|
|
|
74/jump-if-equal break/disp8
|
2019-12-08 21:56:46 +00:00
|
|
|
# if match(stmt, curr) return curr
|
2019-11-09 20:09:20 +00:00
|
|
|
{
|
2019-11-10 03:04:48 +00:00
|
|
|
(mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax
|
2019-11-09 20:09:20 +00:00
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
74/jump-if-equal break/disp8
|
|
|
|
89/<- %eax 1/r32/ecx
|
|
|
|
eb/jump $find-matching-function:end/disp8
|
|
|
|
}
|
|
|
|
# curr = curr->next
|
2019-11-16 02:41:45 +00:00
|
|
|
8b/-> *(ecx+0x10) 1/r32/ecx # Function-next
|
2019-11-09 20:09:20 +00:00
|
|
|
eb/jump loop/disp8
|
|
|
|
}
|
|
|
|
# return null
|
|
|
|
b8/copy-to-eax 0/imm32
|
|
|
|
$find-matching-function:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
find-matching-primitive: # primitives : (handle primitive), stmt : (handle statement) -> result/eax : (handle primitive)
|
2019-11-16 02:41:45 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
2019-12-08 21:56:46 +00:00
|
|
|
# var curr/ecx : (handle primitive) = primitives
|
2019-11-16 02:41:45 +00:00
|
|
|
8b/-> *(ebp+8) 1/r32/ecx
|
|
|
|
{
|
2019-11-18 04:54:39 +00:00
|
|
|
$find-matching-primitive:loop:
|
2019-11-16 02:41:45 +00:00
|
|
|
# if (curr == null) break
|
|
|
|
81 7/subop/compare %ecx 0/imm32
|
2019-12-26 08:28:16 +00:00
|
|
|
0f 84/jump-if-equal break/disp32
|
|
|
|
#? (write-buffered Stderr "prim: ")
|
|
|
|
#? (write-buffered Stderr *ecx) # Primitive-name
|
|
|
|
#? (write-buffered Stderr " => ")
|
|
|
|
#? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name
|
|
|
|
#? (write-buffered Stderr "\n")
|
|
|
|
#? (flush Stderr)
|
2019-11-16 02:41:45 +00:00
|
|
|
# if match(curr, stmt) return curr
|
|
|
|
{
|
|
|
|
(mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
74/jump-if-equal break/disp8
|
|
|
|
89/<- %eax 1/r32/ecx
|
2019-12-26 08:28:16 +00:00
|
|
|
eb/jump $find-matching-primitive:end/disp8
|
2019-11-16 02:41:45 +00:00
|
|
|
}
|
2019-11-18 04:54:39 +00:00
|
|
|
$find-matching-primitive:next-primitive:
|
2019-11-16 02:41:45 +00:00
|
|
|
# curr = curr->next
|
2019-12-26 10:02:57 +00:00
|
|
|
8b/-> *(ecx+0x20) 1/r32/ecx # Primitive-next
|
2019-12-26 08:28:16 +00:00
|
|
|
e9/jump loop/disp32
|
2019-11-16 02:41:45 +00:00
|
|
|
}
|
|
|
|
# return null
|
|
|
|
b8/copy-to-eax 0/imm32
|
|
|
|
$find-matching-primitive:end:
|
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
mu-stmt-matches-function?: # stmt : (handle statement), function : (handle function) => result/eax : boolean
|
2019-11-09 17:00:42 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
|
|
|
# return primitive->name == stmt->operation
|
|
|
|
8b/-> *(ebp+8) 1/r32/ecx
|
|
|
|
8b/-> *(ebp+0xc) 0/r32/eax
|
2019-11-26 05:00:07 +00:00
|
|
|
(string-equal? *(ecx+4) *eax) # Stmt1-operation, Primitive-name => eax
|
2019-11-10 03:04:48 +00:00
|
|
|
$mu-stmt-matches-function?:end:
|
2019-11-09 17:00:42 +00:00
|
|
|
# . restore registers
|
|
|
|
59/pop-to-ecx
|
2019-11-09 01:31:11 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
mu-stmt-matches-primitive?: # stmt : (handle statement), primitive : (handle primitive) => result/eax : boolean
|
2019-11-18 04:54:39 +00:00
|
|
|
# A mu stmt matches a primitive if the name matches, all the inout vars
|
|
|
|
# match, and all the output vars match.
|
|
|
|
# Vars match if types match and registers match.
|
|
|
|
# In addition, a stmt output matches a primitive's output if types match
|
|
|
|
# and the primitive has a wildcard register.
|
2019-11-16 02:41:45 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
51/push-ecx
|
2019-11-18 04:54:39 +00:00
|
|
|
52/push-edx
|
|
|
|
53/push-ebx
|
|
|
|
56/push-esi
|
|
|
|
57/push-edi
|
|
|
|
# ecx = stmt
|
2019-11-16 02:41:45 +00:00
|
|
|
8b/-> *(ebp+8) 1/r32/ecx
|
2019-11-18 04:54:39 +00:00
|
|
|
# edx = primitive
|
|
|
|
8b/-> *(ebp+0xc) 2/r32/edx
|
|
|
|
{
|
|
|
|
$mu-stmt-matches-primitive?:check-name:
|
|
|
|
# if (primitive->name != stmt->operation) return false
|
2019-11-26 05:00:07 +00:00
|
|
|
(string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax
|
2019-11-18 04:54:39 +00:00
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
b8/copy-to-eax 0/imm32
|
|
|
|
e9/jump $mu-stmt-matches-primitive?:end/disp32
|
|
|
|
}
|
|
|
|
$mu-stmt-matches-primitive?:check-inouts:
|
2019-11-27 02:07:55 +00:00
|
|
|
# for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts)
|
2019-11-26 05:00:07 +00:00
|
|
|
8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts
|
2019-11-18 04:54:39 +00:00
|
|
|
8b/-> *(edx+4) 7/r32/edi # Primitive-inouts
|
|
|
|
{
|
2019-12-26 08:28:16 +00:00
|
|
|
# if (curr == 0 && curr2 == 0) move on to check outputs
|
2019-11-18 04:54:39 +00:00
|
|
|
{
|
|
|
|
81 7/subop/compare %esi 0/imm32
|
|
|
|
75/jump-if-not-equal break/disp8
|
2019-11-30 22:16:05 +00:00
|
|
|
$mu-stmt-matches-primitive?:stmt-inout-is-null:
|
2019-11-18 04:54:39 +00:00
|
|
|
{
|
|
|
|
81 7/subop/compare %edi 0/imm32
|
|
|
|
75/jump-if-not-equal break/disp8
|
2019-12-26 08:28:16 +00:00
|
|
|
#
|
|
|
|
e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32
|
2019-11-18 04:54:39 +00:00
|
|
|
}
|
|
|
|
# return false
|
2019-11-30 22:16:05 +00:00
|
|
|
b8/copy-to-eax 0/imm32/false
|
2019-11-18 04:54:39 +00:00
|
|
|
e9/jump $mu-stmt-matches-primitive?:end/disp32
|
|
|
|
}
|
|
|
|
# if (curr2 == 0) return false
|
|
|
|
{
|
|
|
|
81 7/subop/compare %edi 0/imm32
|
|
|
|
75/jump-if-not-equal break/disp8
|
2019-11-30 22:16:05 +00:00
|
|
|
$mu-stmt-matches-primitive?:prim-inout-is-null:
|
|
|
|
b8/copy-to-eax 0/imm32/false
|
2019-11-18 04:54:39 +00:00
|
|
|
e9/jump $mu-stmt-matches-primitive?:end/disp32
|
|
|
|
}
|
|
|
|
# if (curr != curr2) return false
|
|
|
|
{
|
|
|
|
(operand-matches-primitive? *esi *edi) # => eax
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
75/jump-if-not-equal break/disp8
|
2019-11-30 22:16:05 +00:00
|
|
|
b8/copy-to-eax 0/imm32/false
|
2019-11-18 04:54:39 +00:00
|
|
|
e9/jump $mu-stmt-matches-primitive?:end/disp32
|
|
|
|
}
|
|
|
|
# curr=curr->next
|
2019-11-27 02:07:55 +00:00
|
|
|
8b/-> *(esi+4) 6/r32/esi # Operand-next
|
2019-11-18 04:54:39 +00:00
|
|
|
# curr2=curr2->next
|
2019-11-27 02:07:55 +00:00
|
|
|
8b/-> *(edi+4) 7/r32/edi # Operand-next
|
|
|
|
eb/jump loop/disp8
|
2019-11-18 04:54:39 +00:00
|
|
|
}
|
|
|
|
$mu-stmt-matches-primitive?:check-outputs:
|
2019-11-27 02:07:55 +00:00
|
|
|
# for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs)
|
2019-11-26 05:00:07 +00:00
|
|
|
8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs
|
2019-11-18 04:54:39 +00:00
|
|
|
8b/-> *(edx+8) 7/r32/edi # Primitive-outputs
|
|
|
|
{
|
|
|
|
# if (curr == 0) return (curr2 == 0)
|
|
|
|
{
|
2019-12-26 08:28:16 +00:00
|
|
|
$mu-stmt-matches-primitive?:check-output:
|
2019-11-18 04:54:39 +00:00
|
|
|
81 7/subop/compare %esi 0/imm32
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
{
|
|
|
|
81 7/subop/compare %edi 0/imm32
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
# return true
|
|
|
|
b8/copy-to-eax 1/imm32
|
|
|
|
e9/jump $mu-stmt-matches-primitive?:end/disp32
|
|
|
|
}
|
|
|
|
# return false
|
|
|
|
b8/copy-to-eax 0/imm32
|
|
|
|
e9/jump $mu-stmt-matches-primitive?:end/disp32
|
|
|
|
}
|
|
|
|
# if (curr2 == 0) return false
|
|
|
|
{
|
|
|
|
81 7/subop/compare %edi 0/imm32
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
b8/copy-to-eax 0/imm32
|
|
|
|
e9/jump $mu-stmt-matches-primitive?:end/disp32
|
|
|
|
}
|
|
|
|
# if (curr != curr2) return false
|
|
|
|
{
|
2019-11-18 09:13:31 +00:00
|
|
|
(operand-matches-primitive? *esi *edi) # => eax
|
2019-11-18 04:54:39 +00:00
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
75/jump-if-not-equal break/disp8
|
|
|
|
b8/copy-to-eax 0/imm32
|
|
|
|
e9/jump $mu-stmt-matches-primitive?:end/disp32
|
|
|
|
}
|
|
|
|
# curr=curr->next
|
2019-12-26 08:28:16 +00:00
|
|
|
8b/-> *(esi+4) 6/r32/esi # Operand-next
|
2019-11-18 04:54:39 +00:00
|
|
|
# curr2=curr2->next
|
2019-12-26 08:28:16 +00:00
|
|
|
8b/-> *(edi+4) 7/r32/edi # Operand-next
|
2019-11-27 02:07:55 +00:00
|
|
|
eb/jump loop/disp8
|
2019-11-18 04:54:39 +00:00
|
|
|
}
|
|
|
|
$mu-stmt-matches-primitive?:return-true:
|
|
|
|
b8/copy-to-eax 1/imm32
|
2019-11-16 02:41:45 +00:00
|
|
|
$mu-stmt-matches-primitive?:end:
|
|
|
|
# . restore registers
|
2019-11-18 04:54:39 +00:00
|
|
|
5f/pop-to-edi
|
|
|
|
5e/pop-to-esi
|
|
|
|
5b/pop-to-ebx
|
|
|
|
5a/pop-to-edx
|
2019-11-16 02:41:45 +00:00
|
|
|
59/pop-to-ecx
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-08 21:56:46 +00:00
|
|
|
operand-matches-primitive?: # var : (handle var), primout-var : (handle var) => result/eax : boolean
|
2019-11-18 04:54:39 +00:00
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# . save registers
|
|
|
|
56/push-esi
|
|
|
|
57/push-edi
|
|
|
|
# esi = var
|
|
|
|
8b/-> *(ebp+8) 6/r32/esi
|
|
|
|
# edi = primout-var
|
|
|
|
8b/-> *(ebp+0xc) 7/r32/edi
|
|
|
|
# if (var->type != primout-var->type) return false
|
2019-11-27 01:41:25 +00:00
|
|
|
8b/-> *(esi+4) 0/r32/eax # Var-type
|
|
|
|
39/compare *(edi+4) 0/r32/eax # Var-type
|
|
|
|
b8/copy-to-eax 0/imm32/false
|
|
|
|
75/jump-if-not-equal $operand-matches-primitive?:end/disp8
|
2019-11-18 04:54:39 +00:00
|
|
|
# return false if var->register doesn't match primout-var->register
|
|
|
|
{
|
|
|
|
# if addresses are equal, don't return here
|
|
|
|
8b/-> *(esi+0x10) 0/r32/eax
|
|
|
|
39/compare *(edi+0x10) 0/r32/eax
|
|
|
|
74/jump-if-equal break/disp8
|
|
|
|
# if either address is 0, return false
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result
|
|
|
|
81 7/subop/compare *(edi+0x10) 0/imm32
|
|
|
|
74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result
|
|
|
|
# if primout-var->register is "*", return true
|
|
|
|
(string-equal? *(edi+0x10) "*") # Var-register
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
b8/copy-to-eax 1/imm32/true
|
|
|
|
75/jump-if-not-equal $operand-matches-primitive?:end/disp8
|
|
|
|
# if string contents don't match, return false
|
|
|
|
(string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register
|
|
|
|
3d/compare-eax-and 0/imm32
|
|
|
|
b8/copy-to-eax 0/imm32/false
|
|
|
|
74/jump-if-equal $operand-matches-primitive?:end/disp8
|
|
|
|
}
|
|
|
|
# return true
|
|
|
|
b8/copy-to-eax 1/imm32/true
|
2019-11-18 09:13:31 +00:00
|
|
|
$operand-matches-primitive?:end:
|
2019-11-18 04:54:39 +00:00
|
|
|
# . restore registers
|
|
|
|
5f/pop-to-edi
|
|
|
|
5e/pop-to-esi
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-09 01:31:11 +00:00
|
|
|
test-emit-subx-statement-primitive:
|
2019-11-09 17:00:42 +00:00
|
|
|
# Primitive operation on a variable on the stack.
|
2019-11-09 01:31:11 +00:00
|
|
|
# increment foo
|
|
|
|
# =>
|
|
|
|
# ff 0/subop/increment *(ebp-8)
|
|
|
|
#
|
2019-11-09 17:00:42 +00:00
|
|
|
# There's a variable on the var stack as follows:
|
2019-11-09 01:31:11 +00:00
|
|
|
# name: 'foo'
|
|
|
|
# type: int
|
2019-11-15 01:39:32 +00:00
|
|
|
# stack-offset: -8
|
2019-11-09 01:31:11 +00:00
|
|
|
#
|
2019-11-09 17:00:42 +00:00
|
|
|
# There's a primitive with this info:
|
2019-11-09 01:31:11 +00:00
|
|
|
# name: 'increment'
|
2019-11-16 02:41:45 +00:00
|
|
|
# inouts: int/mem
|
2019-11-09 01:31:11 +00:00
|
|
|
# value: 'ff 0/subop/increment'
|
|
|
|
#
|
2019-11-09 17:00:42 +00:00
|
|
|
# There's nothing in functions.
|
2019-11-09 01:31:11 +00:00
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-foo/ecx : (ref var)
|
2019-11-15 01:17:34 +00:00
|
|
|
68/push 0/imm32/no-register
|
|
|
|
68/push -8/imm32/stack-offset
|
2019-11-11 03:09:38 +00:00
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
2019-11-09 01:31:11 +00:00
|
|
|
68/push "foo"/imm32
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var operand/ebx : (ref list var)
|
2019-11-11 03:09:38 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
51/push-ecx/var-foo
|
2019-11-18 04:54:39 +00:00
|
|
|
89/<- %ebx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var stmt/esi : (ref statement)
|
2019-11-09 01:31:11 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
68/push 0/imm32/outputs
|
2019-11-18 04:54:39 +00:00
|
|
|
53/push-ebx/operands
|
2019-11-09 01:31:11 +00:00
|
|
|
68/push "increment"/imm32/operation
|
2019-11-26 05:00:07 +00:00
|
|
|
68/push 1/imm32
|
2019-11-11 03:09:38 +00:00
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var primitives/ebx : (ref primitive)
|
2019-11-09 01:31:11 +00:00
|
|
|
68/push 0/imm32/next
|
2019-12-26 10:02:57 +00:00
|
|
|
68/push 0/imm32/output-is-write-only
|
2019-11-16 02:41:45 +00:00
|
|
|
68/push 0/imm32/no-imm32
|
|
|
|
68/push 0/imm32/no-r32
|
|
|
|
68/push 1/imm32/rm32-is-first-inout
|
|
|
|
68/push "ff 0/subop/increment"/imm32/subx-name
|
2019-11-11 03:09:38 +00:00
|
|
|
68/push 0/imm32/outputs
|
2019-11-18 04:54:39 +00:00
|
|
|
53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call
|
2019-11-09 01:31:11 +00:00
|
|
|
68/push "increment"/imm32/name
|
|
|
|
89/<- %ebx 4/r32/esp
|
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-statement _test-output-buffered-file %esi %ebx 0)
|
2019-11-09 01:31:11 +00:00
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
2019-11-18 09:13:31 +00:00
|
|
|
(check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive")
|
2019-11-16 02:41:45 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-emit-subx-statement-primitive-register:
|
|
|
|
# Primitive operation on a variable in a register.
|
|
|
|
# foo <- increment
|
|
|
|
# =>
|
|
|
|
# ff 0/subop/increment %eax # sub-optimal, but should suffice
|
|
|
|
#
|
|
|
|
# There's a variable on the var stack as follows:
|
|
|
|
# name: 'foo'
|
|
|
|
# type: int
|
|
|
|
# register: 'eax'
|
|
|
|
#
|
|
|
|
# There's a primitive with this info:
|
|
|
|
# name: 'increment'
|
2019-11-18 04:54:39 +00:00
|
|
|
# out: int/reg
|
2019-11-16 02:41:45 +00:00
|
|
|
# value: 'ff 0/subop/increment'
|
|
|
|
#
|
|
|
|
# There's nothing in functions.
|
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-foo/ecx : (ref var) in eax
|
2019-11-16 02:41:45 +00:00
|
|
|
68/push "eax"/imm32/register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "foo"/imm32
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var operand/ebx : (ref list var)
|
2019-11-16 02:41:45 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
51/push-ecx/var-foo
|
2019-11-18 04:54:39 +00:00
|
|
|
89/<- %ebx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var stmt/esi : (ref statement)
|
2019-11-16 02:41:45 +00:00
|
|
|
68/push 0/imm32/next
|
2019-11-18 04:54:39 +00:00
|
|
|
53/push-ebx/outputs
|
2019-11-16 02:41:45 +00:00
|
|
|
68/push 0/imm32/inouts
|
|
|
|
68/push "increment"/imm32/operation
|
2019-11-26 05:00:07 +00:00
|
|
|
68/push 1/imm32
|
2019-11-16 02:41:45 +00:00
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var formal-var/ebx : (ref var) in any register
|
2019-11-16 02:41:45 +00:00
|
|
|
68/push Any-register/imm32
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "dummy"/imm32
|
|
|
|
89/<- %ebx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var operand/ebx : (ref list var)
|
2019-11-16 02:41:45 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
53/push-ebx/formal-var
|
|
|
|
89/<- %ebx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var primitives/ebx : (ref primitive)
|
2019-11-16 02:41:45 +00:00
|
|
|
68/push 0/imm32/next
|
2019-12-26 10:02:57 +00:00
|
|
|
68/push 0/imm32/output-is-write-only
|
2019-11-16 02:41:45 +00:00
|
|
|
68/push 0/imm32/no-imm32
|
|
|
|
68/push 0/imm32/no-r32
|
|
|
|
68/push 3/imm32/rm32-in-first-output
|
|
|
|
68/push "ff 0/subop/increment"/imm32/subx-name
|
|
|
|
53/push-ebx/outputs
|
|
|
|
68/push 0/imm32/inouts
|
|
|
|
68/push "increment"/imm32/name
|
|
|
|
89/<- %ebx 4/r32/esp
|
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-statement _test-output-buffered-file %esi %ebx 0)
|
2019-11-16 02:41:45 +00:00
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
2019-11-18 09:13:31 +00:00
|
|
|
(check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register")
|
2019-11-18 04:54:39 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-emit-subx-statement-select-primitive:
|
|
|
|
# Select the right primitive between overloads.
|
|
|
|
# foo <- increment
|
|
|
|
# =>
|
|
|
|
# ff 0/subop/increment %eax # sub-optimal, but should suffice
|
|
|
|
#
|
|
|
|
# There's a variable on the var stack as follows:
|
|
|
|
# name: 'foo'
|
|
|
|
# type: int
|
|
|
|
# register: 'eax'
|
|
|
|
#
|
|
|
|
# There's two primitives, as follows:
|
|
|
|
# - name: 'increment'
|
|
|
|
# out: int/reg
|
|
|
|
# value: 'ff 0/subop/increment'
|
|
|
|
# - name: 'increment'
|
|
|
|
# inout: int/mem
|
|
|
|
# value: 'ff 0/subop/increment'
|
|
|
|
#
|
|
|
|
# There's nothing in functions.
|
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-foo/ecx : (ref var) in eax
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push "eax"/imm32/register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "foo"/imm32
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var real-outputs/edi : (ref list var)
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
51/push-ecx/var-foo
|
|
|
|
89/<- %edi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var stmt/esi : (ref statement)
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
57/push-edi/outputs
|
|
|
|
68/push 0/imm32/inouts
|
|
|
|
68/push "increment"/imm32/operation
|
2019-11-26 05:00:07 +00:00
|
|
|
68/push 1/imm32
|
2019-11-18 04:54:39 +00:00
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var formal-var/ebx : (ref var) in any register
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push Any-register/imm32
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "dummy"/imm32
|
|
|
|
89/<- %ebx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var formal-outputs/ebx : (ref list var) = {formal-var, 0}
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
53/push-ebx/formal-var
|
|
|
|
89/<- %ebx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var primitive1/ebx : (ref primitive)
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push 0/imm32/next
|
2019-12-26 10:02:57 +00:00
|
|
|
68/push 0/imm32/output-is-write-only
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push 0/imm32/no-imm32
|
|
|
|
68/push 0/imm32/no-r32
|
|
|
|
68/push 3/imm32/rm32-in-first-output
|
|
|
|
68/push "ff 0/subop/increment"/imm32/subx-name
|
|
|
|
53/push-ebx/outputs/formal-outputs
|
|
|
|
68/push 0/imm32/inouts
|
|
|
|
68/push "increment"/imm32/name
|
|
|
|
89/<- %ebx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var primitives/ebx : (ref primitive)
|
2019-11-18 04:54:39 +00:00
|
|
|
53/push-ebx/next
|
2019-12-26 10:02:57 +00:00
|
|
|
68/push 0/imm32/output-is-write-only
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push 0/imm32/no-imm32
|
|
|
|
68/push 0/imm32/no-r32
|
|
|
|
68/push 1/imm32/rm32-is-first-inout
|
|
|
|
68/push "ff 0/subop/increment"/imm32/subx-name
|
|
|
|
68/push 0/imm32/outputs
|
|
|
|
57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call
|
|
|
|
68/push "increment"/imm32/name
|
|
|
|
89/<- %ebx 4/r32/esp
|
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-statement _test-output-buffered-file %esi %ebx 0)
|
2019-11-18 04:54:39 +00:00
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
2019-11-18 09:13:31 +00:00
|
|
|
(check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive")
|
2019-11-18 04:54:39 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-emit-subx-statement-select-primitive-2:
|
|
|
|
# Select the right primitive between overloads.
|
|
|
|
# foo <- increment
|
|
|
|
# =>
|
|
|
|
# ff 0/subop/increment %eax # sub-optimal, but should suffice
|
|
|
|
#
|
|
|
|
# There's a variable on the var stack as follows:
|
|
|
|
# name: 'foo'
|
|
|
|
# type: int
|
|
|
|
# register: 'eax'
|
|
|
|
#
|
|
|
|
# There's two primitives, as follows:
|
|
|
|
# - name: 'increment'
|
|
|
|
# out: int/reg
|
|
|
|
# value: 'ff 0/subop/increment'
|
|
|
|
# - name: 'increment'
|
|
|
|
# inout: int/mem
|
|
|
|
# value: 'ff 0/subop/increment'
|
|
|
|
#
|
|
|
|
# There's nothing in functions.
|
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-foo/ecx : (ref var) in eax
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push "eax"/imm32/register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "foo"/imm32
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var inouts/edi : (ref list var)
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
51/push-ecx/var-foo
|
|
|
|
89/<- %edi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var stmt/esi : (ref statement)
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
68/push 0/imm32/outputs
|
|
|
|
57/push-edi/inouts
|
|
|
|
68/push "increment"/imm32/operation
|
2019-11-26 05:00:07 +00:00
|
|
|
68/push 1/imm32
|
2019-11-18 04:54:39 +00:00
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var formal-var/ebx : (ref var) in any register
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push Any-register/imm32
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "dummy"/imm32
|
|
|
|
89/<- %ebx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var operand/ebx : (ref list var)
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
53/push-ebx/formal-var
|
|
|
|
89/<- %ebx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var primitive1/ebx : primitive
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push 0/imm32/next
|
2019-12-26 10:02:57 +00:00
|
|
|
68/push 0/imm32/output-is-write-only
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push 0/imm32/no-imm32
|
|
|
|
68/push 0/imm32/no-r32
|
|
|
|
68/push 3/imm32/rm32-in-first-output
|
|
|
|
68/push "ff 0/subop/increment"/imm32/subx-name
|
|
|
|
53/push-ebx/outputs/formal-outputs
|
|
|
|
68/push 0/imm32/inouts
|
|
|
|
68/push "increment"/imm32/name
|
|
|
|
89/<- %ebx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var primitives/ebx : (ref primitive)
|
2019-11-18 04:54:39 +00:00
|
|
|
53/push-ebx/next
|
2019-12-26 10:02:57 +00:00
|
|
|
68/push 0/imm32/output-is-write-only
|
2019-11-18 04:54:39 +00:00
|
|
|
68/push 0/imm32/no-imm32
|
|
|
|
68/push 0/imm32/no-r32
|
|
|
|
68/push 1/imm32/rm32-is-first-inout
|
|
|
|
68/push "ff 0/subop/increment"/imm32/subx-name
|
|
|
|
68/push 0/imm32/outputs
|
|
|
|
57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call
|
|
|
|
68/push "increment"/imm32/name
|
|
|
|
89/<- %ebx 4/r32/esp
|
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-statement _test-output-buffered-file %esi %ebx 0)
|
2019-11-18 04:54:39 +00:00
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
2019-11-18 08:24:24 +00:00
|
|
|
#? # }}}
|
|
|
|
# check output
|
2019-11-18 09:13:31 +00:00
|
|
|
(check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2")
|
2019-11-18 08:24:24 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-18 09:13:31 +00:00
|
|
|
test-increment-register:
|
2019-11-18 08:24:24 +00:00
|
|
|
# Select the right primitive between overloads.
|
|
|
|
# foo <- increment
|
|
|
|
# =>
|
2019-12-26 08:11:25 +00:00
|
|
|
# 50/increment-eax
|
2019-11-18 08:24:24 +00:00
|
|
|
#
|
|
|
|
# There's a variable on the var stack as follows:
|
|
|
|
# name: 'foo'
|
|
|
|
# type: int
|
|
|
|
# register: 'eax'
|
|
|
|
#
|
|
|
|
# Primitives are the global definitions.
|
|
|
|
#
|
|
|
|
# There are no functions defined.
|
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-foo/ecx : (ref var) in eax
|
2019-11-18 08:24:24 +00:00
|
|
|
68/push "eax"/imm32/register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "foo"/imm32
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var real-outputs/edi : (ref list var)
|
2019-11-18 08:24:24 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
51/push-ecx/var-foo
|
|
|
|
89/<- %edi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var stmt/esi : (ref statement)
|
2019-11-18 08:24:24 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
57/push-edi/outputs
|
|
|
|
68/push 0/imm32/inouts
|
|
|
|
68/push "increment"/imm32/operation
|
2019-11-26 05:00:07 +00:00
|
|
|
68/push 1/imm32
|
2019-11-18 08:24:24 +00:00
|
|
|
89/<- %esi 4/r32/esp
|
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-statement _test-output-buffered-file %esi Primitives 0)
|
2019-11-18 08:24:24 +00:00
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
2019-12-26 08:11:25 +00:00
|
|
|
(check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
|
2019-11-18 08:24:24 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-18 09:13:31 +00:00
|
|
|
test-increment-var:
|
2019-11-18 08:24:24 +00:00
|
|
|
# Select the right primitive between overloads.
|
|
|
|
# foo <- increment
|
|
|
|
# =>
|
|
|
|
# ff 0/subop/increment %eax # sub-optimal, but should suffice
|
|
|
|
#
|
|
|
|
# There's a variable on the var stack as follows:
|
|
|
|
# name: 'foo'
|
|
|
|
# type: int
|
|
|
|
# register: 'eax'
|
|
|
|
#
|
|
|
|
# Primitives are the global definitions.
|
|
|
|
#
|
|
|
|
# There are no functions defined.
|
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-foo/ecx : (ref var) in eax
|
2019-11-18 08:24:24 +00:00
|
|
|
68/push "eax"/imm32/register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "foo"/imm32
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var inouts/edi : (ref list var)
|
2019-11-18 08:24:24 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
51/push-ecx/var-foo
|
|
|
|
89/<- %edi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var stmt/esi : (ref statement)
|
2019-11-18 08:24:24 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
68/push 0/imm32/outputs
|
|
|
|
57/push-edi/inouts
|
|
|
|
68/push "increment"/imm32/operation
|
2019-11-26 05:00:07 +00:00
|
|
|
68/push 1/imm32
|
2019-11-18 08:24:24 +00:00
|
|
|
89/<- %esi 4/r32/esp
|
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-statement _test-output-buffered-file %esi Primitives 0)
|
2019-11-18 08:24:24 +00:00
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
2019-11-18 04:54:39 +00:00
|
|
|
#? # }}}
|
|
|
|
# check output
|
2019-11-18 09:13:31 +00:00
|
|
|
(check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-add-reg-to-reg:
|
|
|
|
# var1/reg <- add var2/reg
|
|
|
|
# =>
|
2019-12-26 08:28:16 +00:00
|
|
|
# 01/add %var1 var2
|
2019-11-18 09:13:31 +00:00
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-var1/ecx : (ref var) in eax
|
2019-11-18 09:13:31 +00:00
|
|
|
68/push "eax"/imm32/register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "var1"/imm32
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-var2/edx : (ref var) in ecx
|
2019-11-18 09:13:31 +00:00
|
|
|
68/push "ecx"/imm32/register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "var2"/imm32
|
|
|
|
89/<- %edx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var inouts/esi : (ref list var2)
|
2019-11-18 09:13:31 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
52/push-edx/var-var2
|
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var outputs/edi : (ref list var1)
|
2019-11-18 09:13:31 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
51/push-ecx/var-var1
|
|
|
|
89/<- %edi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var stmt/esi : (ref statement)
|
2019-11-18 09:13:31 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
57/push-edi/outputs
|
|
|
|
56/push-esi/inouts
|
|
|
|
68/push "add"/imm32/operation
|
2019-11-26 05:00:07 +00:00
|
|
|
68/push 1/imm32
|
2019-11-18 09:13:31 +00:00
|
|
|
89/<- %esi 4/r32/esp
|
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-statement _test-output-buffered-file %esi Primitives 0)
|
2019-11-18 09:13:31 +00:00
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
2019-12-26 10:21:55 +00:00
|
|
|
(check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
|
2019-11-09 01:31:11 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-27 06:11:23 +00:00
|
|
|
test-add-reg-to-mem:
|
|
|
|
# add-to var1 var2/reg
|
|
|
|
# =>
|
2019-12-26 08:28:16 +00:00
|
|
|
# 01/add *(ebp+__) var2
|
2019-11-27 06:11:23 +00:00
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-var1/ecx : (ref var)
|
2019-11-27 06:11:23 +00:00
|
|
|
68/push 0/imm32/no-register
|
|
|
|
68/push 8/imm32/stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "var1"/imm32
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-var2/edx : (ref var) in ecx
|
2019-11-27 06:11:23 +00:00
|
|
|
68/push "ecx"/imm32/register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "var2"/imm32
|
|
|
|
89/<- %edx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var inouts/esi : (ref list var2)
|
2019-11-27 06:11:23 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
52/push-edx/var-var2
|
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var inouts = (ref list var1 var2)
|
2019-11-27 06:11:23 +00:00
|
|
|
56/push-esi/next
|
|
|
|
51/push-ecx/var-var1
|
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var stmt/esi : (ref statement)
|
2019-11-27 06:11:23 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
68/push 0/imm32/outputs
|
|
|
|
56/push-esi/inouts
|
|
|
|
68/push "add-to"/imm32/operation
|
|
|
|
68/push 1/imm32
|
|
|
|
89/<- %esi 4/r32/esp
|
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-statement _test-output-buffered-file %esi Primitives 0)
|
2019-11-27 06:11:23 +00:00
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
2019-12-26 10:21:55 +00:00
|
|
|
(check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
|
2019-11-27 06:11:23 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-add-mem-to-reg:
|
|
|
|
# var1/reg <- add var2
|
|
|
|
# =>
|
2019-12-26 08:28:16 +00:00
|
|
|
# 03/add *(ebp+__) var1
|
2019-11-27 06:11:23 +00:00
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-var1/ecx : (ref var) in eax
|
2019-11-27 06:11:23 +00:00
|
|
|
68/push "eax"/imm32/register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "var1"/imm32
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-var2/edx : (ref var)
|
2019-11-27 06:11:23 +00:00
|
|
|
68/push 0/imm32/no-register
|
|
|
|
68/push 8/imm32/stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "var2"/imm32
|
|
|
|
89/<- %edx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var inouts/esi : (ref list var2)
|
2019-11-27 06:11:23 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
52/push-edx/var-var2
|
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var outputs/edi : (ref list var1)
|
2019-11-27 06:11:23 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
51/push-ecx/var-var1
|
|
|
|
89/<- %edi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var stmt/esi : (ref statement)
|
2019-11-27 06:11:23 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
57/push-edi/outputs
|
|
|
|
56/push-esi/inouts
|
|
|
|
68/push "add"/imm32/operation
|
|
|
|
68/push 1/imm32
|
|
|
|
89/<- %esi 4/r32/esp
|
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-statement _test-output-buffered-file %esi Primitives 0)
|
2019-11-27 06:11:23 +00:00
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
2019-12-26 08:28:16 +00:00
|
|
|
(check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
|
2019-11-27 06:11:23 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-12-26 08:28:16 +00:00
|
|
|
test-add-literal-to-eax:
|
2019-11-19 00:30:30 +00:00
|
|
|
# var1/eax <- add 0x34
|
|
|
|
# =>
|
2019-12-26 08:28:16 +00:00
|
|
|
# 05/add-to-eax 0x34/imm32
|
2019-11-19 00:30:30 +00:00
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-var1/ecx : (ref var) in eax
|
2019-11-19 00:30:30 +00:00
|
|
|
68/push "eax"/imm32/register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "var1"/imm32
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-var2/edx : (ref var) literal
|
2019-11-19 00:30:30 +00:00
|
|
|
68/push 0/imm32/no-register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 0/imm32/type-literal
|
|
|
|
68/push "0x34"/imm32
|
|
|
|
89/<- %edx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var inouts/esi : (ref list var2)
|
2019-11-19 00:30:30 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
52/push-edx/var-var2
|
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var outputs/edi : (ref list var1)
|
2019-11-19 00:30:30 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
51/push-ecx/var-var1
|
|
|
|
89/<- %edi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var stmt/esi : (ref statement)
|
2019-11-19 00:30:30 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
57/push-edi/outputs
|
|
|
|
56/push-esi/inouts
|
|
|
|
68/push "add"/imm32/operation
|
2019-11-26 05:00:07 +00:00
|
|
|
68/push 1/imm32
|
2019-11-19 00:30:30 +00:00
|
|
|
89/<- %esi 4/r32/esp
|
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-statement _test-output-buffered-file %esi Primitives 0)
|
2019-11-19 00:30:30 +00:00
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
2019-12-26 08:28:16 +00:00
|
|
|
(check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
test-add-literal-to-reg:
|
|
|
|
# var1/ecx <- add 0x34
|
|
|
|
# =>
|
|
|
|
# 81 0/subop/add %ecx 0x34/imm32
|
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-output-stream)
|
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
|
|
|
# var var-var1/ecx : (ref var) in ecx
|
|
|
|
68/push "ecx"/imm32/register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "var1"/imm32
|
|
|
|
89/<- %ecx 4/r32/esp
|
|
|
|
# var var-var2/edx : (ref var) literal
|
|
|
|
68/push 0/imm32/no-register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 0/imm32/type-literal
|
|
|
|
68/push "0x34"/imm32
|
|
|
|
89/<- %edx 4/r32/esp
|
|
|
|
# var inouts/esi : (ref list var2)
|
|
|
|
68/push 0/imm32/next
|
|
|
|
52/push-edx/var-var2
|
|
|
|
89/<- %esi 4/r32/esp
|
|
|
|
# var outputs/edi : (ref list var1)
|
|
|
|
68/push 0/imm32/next
|
|
|
|
51/push-ecx/var-var1
|
|
|
|
89/<- %edi 4/r32/esp
|
|
|
|
# var stmt/esi : (ref statement)
|
|
|
|
68/push 0/imm32/next
|
|
|
|
57/push-edi/outputs
|
|
|
|
56/push-esi/inouts
|
|
|
|
68/push "add"/imm32/operation
|
|
|
|
68/push 1/imm32
|
|
|
|
89/<- %esi 4/r32/esp
|
|
|
|
# convert
|
|
|
|
(emit-subx-statement _test-output-buffered-file %esi Primitives 0)
|
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
|
|
|
(check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
|
2019-11-19 00:30:30 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-27 02:07:55 +00:00
|
|
|
test-add-literal-to-mem:
|
|
|
|
# add-to var1, 0x34
|
|
|
|
# =>
|
|
|
|
# 81 0/subop/add %eax 0x34/imm32
|
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-var1/ecx : (ref var)
|
2019-11-27 02:07:55 +00:00
|
|
|
68/push 0/imm32/no-register
|
|
|
|
68/push 8/imm32/stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "var1"/imm32
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-var2/edx : (ref var) literal
|
2019-11-27 02:07:55 +00:00
|
|
|
68/push 0/imm32/no-register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 1/imm32/block-depth
|
|
|
|
68/push 0/imm32/type-literal
|
|
|
|
68/push "0x34"/imm32
|
|
|
|
89/<- %edx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var inouts/esi : (ref list var2)
|
2019-11-27 02:07:55 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
52/push-edx/var-var2
|
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var inouts = (ref list var1 inouts)
|
2019-11-27 02:07:55 +00:00
|
|
|
56/push-esi/next
|
|
|
|
51/push-ecx/var-var1
|
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var stmt/esi : (ref statement)
|
2019-11-27 02:07:55 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
68/push 0/imm32/outputs
|
|
|
|
56/push-esi/inouts
|
|
|
|
68/push "add-to"/imm32/operation
|
|
|
|
68/push 1/imm32
|
|
|
|
89/<- %esi 4/r32/esp
|
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-statement _test-output-buffered-file %esi Primitives 0)
|
2019-11-27 02:07:55 +00:00
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
|
|
|
(check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-09 17:00:42 +00:00
|
|
|
test-emit-subx-statement-function-call:
|
|
|
|
# Call a function on a variable on the stack.
|
2019-11-11 03:09:38 +00:00
|
|
|
# f foo
|
2019-11-09 17:00:42 +00:00
|
|
|
# =>
|
|
|
|
# (f2 *(ebp-8))
|
2019-11-11 05:03:33 +00:00
|
|
|
# (Changing the function name supports overloading in general, but here it
|
|
|
|
# just serves to help disambiguate things.)
|
2019-11-09 17:00:42 +00:00
|
|
|
#
|
|
|
|
# There's a variable on the var stack as follows:
|
2019-11-11 03:09:38 +00:00
|
|
|
# name: 'foo'
|
2019-11-09 17:00:42 +00:00
|
|
|
# type: int
|
2019-11-15 01:39:32 +00:00
|
|
|
# stack-offset: -8
|
2019-11-09 17:00:42 +00:00
|
|
|
#
|
|
|
|
# There's nothing in primitives.
|
|
|
|
#
|
|
|
|
# There's a function with this info:
|
|
|
|
# name: 'f'
|
|
|
|
# inout: int/mem
|
|
|
|
# value: 'f2'
|
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-foo/ecx : (ref var)
|
2019-11-15 01:17:34 +00:00
|
|
|
68/push 0/imm32/no-register
|
|
|
|
68/push -8/imm32/stack-offset
|
2019-11-11 03:09:38 +00:00
|
|
|
68/push 0/imm32/block-depth
|
|
|
|
68/push 1/imm32/type-int
|
|
|
|
68/push "foo"/imm32
|
2019-11-09 17:00:42 +00:00
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var operands/esi : (ref list var)
|
2019-11-11 03:09:38 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
51/push-ecx/var-foo
|
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var stmt/esi : (ref statement)
|
2019-11-09 17:00:42 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
68/push 0/imm32/outputs
|
2019-11-11 05:03:33 +00:00
|
|
|
56/push-esi/inouts
|
2019-11-09 17:00:42 +00:00
|
|
|
68/push "f"/imm32/operation
|
2019-11-26 05:00:07 +00:00
|
|
|
68/push 1/imm32
|
2019-11-11 03:09:38 +00:00
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var functions/ebx : (ref function)
|
2019-11-09 17:00:42 +00:00
|
|
|
68/push 0/imm32/next
|
2019-11-11 03:09:38 +00:00
|
|
|
68/push 0/imm32/body
|
|
|
|
68/push 0/imm32/outputs
|
|
|
|
51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call
|
|
|
|
68/push "f2"/imm32/subx-name
|
2019-11-09 17:00:42 +00:00
|
|
|
68/push "f"/imm32/name
|
|
|
|
89/<- %ebx 4/r32/esp
|
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-statement _test-output-buffered-file %esi 0 %ebx)
|
2019-11-09 17:00:42 +00:00
|
|
|
(flush _test-output-buffered-file)
|
2019-11-11 05:03:33 +00:00
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
2019-11-09 17:00:42 +00:00
|
|
|
# check output
|
2019-11-18 09:13:31 +00:00
|
|
|
(check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call")
|
2019-11-09 17:00:42 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-11-19 01:29:50 +00:00
|
|
|
test-emit-subx-statement-function-call-with-literal-arg:
|
|
|
|
# Call a function on a literal.
|
|
|
|
# f 34
|
|
|
|
# =>
|
|
|
|
# (f2 34)
|
|
|
|
#
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# setup
|
|
|
|
(clear-stream _test-output-stream)
|
2019-12-06 06:57:51 +00:00
|
|
|
(clear-stream $_test-output-buffered-file->buffer)
|
2019-12-08 21:56:46 +00:00
|
|
|
# var var-foo/ecx : (ref var) literal
|
2019-11-19 01:29:50 +00:00
|
|
|
68/push 0/imm32/no-register
|
|
|
|
68/push 0/imm32/no-stack-offset
|
|
|
|
68/push 0/imm32/block-depth
|
|
|
|
68/push 0/imm32/type-literal
|
|
|
|
68/push "34"/imm32
|
|
|
|
89/<- %ecx 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var operands/esi : (ref list var)
|
2019-11-19 01:29:50 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
51/push-ecx/var-foo
|
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var stmt/esi : (ref statement)
|
2019-11-19 01:29:50 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
68/push 0/imm32/outputs
|
|
|
|
56/push-esi/inouts
|
|
|
|
68/push "f"/imm32/operation
|
2019-11-26 05:00:07 +00:00
|
|
|
68/push 1/imm32
|
2019-11-19 01:29:50 +00:00
|
|
|
89/<- %esi 4/r32/esp
|
2019-12-08 21:56:46 +00:00
|
|
|
# var functions/ebx : (ref function)
|
2019-11-19 01:29:50 +00:00
|
|
|
68/push 0/imm32/next
|
|
|
|
68/push 0/imm32/body
|
|
|
|
68/push 0/imm32/outputs
|
|
|
|
51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call
|
|
|
|
68/push "f2"/imm32/subx-name
|
|
|
|
68/push "f"/imm32/name
|
|
|
|
89/<- %ebx 4/r32/esp
|
|
|
|
# convert
|
2019-12-23 07:20:44 +00:00
|
|
|
(emit-subx-statement _test-output-buffered-file %esi 0 %ebx)
|
2019-11-19 01:29:50 +00:00
|
|
|
(flush _test-output-buffered-file)
|
|
|
|
#? # dump _test-output-stream {{{
|
|
|
|
#? (write 2 "^")
|
|
|
|
#? (write-stream 2 _test-output-stream)
|
|
|
|
#? (write 2 "$\n")
|
|
|
|
#? (rewind-stream _test-output-stream)
|
|
|
|
#? # }}}
|
|
|
|
# check output
|
|
|
|
(check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg")
|
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
2019-10-30 00:51:54 +00:00
|
|
|
emit-subx-prologue: # out : (address buffered-file)
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
#
|
|
|
|
(write-buffered *(ebp+8) "# . prologue\n")
|
|
|
|
(write-buffered *(ebp+8) "55/push-ebp\n")
|
|
|
|
(write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n")
|
2019-11-09 01:31:11 +00:00
|
|
|
$emit-subx-prologue:end:
|
2019-10-30 00:51:54 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|
|
|
|
|
|
|
|
emit-subx-epilogue: # out : (address buffered-file)
|
|
|
|
# . prologue
|
|
|
|
55/push-ebp
|
|
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
#
|
|
|
|
(write-buffered *(ebp+8) "# . epilogue\n")
|
|
|
|
(write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n")
|
|
|
|
(write-buffered *(ebp+8) "5d/pop-to-ebp\n")
|
|
|
|
(write-buffered *(ebp+8) "c3/return\n")
|
2019-11-09 01:31:11 +00:00
|
|
|
$emit-subx-epilogue:end:
|
2019-10-30 00:51:54 +00:00
|
|
|
# . epilogue
|
|
|
|
89/<- %esp 5/r32/ebp
|
|
|
|
5d/pop-to-ebp
|
|
|
|
c3/return
|