Specification for the

Portia Virtual Machine Language

 

Version:

2004.0

Date:

April 4, 2004

Author:

Kevin Albrecht

Website:

http://kevin.alteu.com/

 


0.     Table of Contents

0.      Table of Contents.. 1

1.      Introduction.. 2

1.1        File Formats and Extensions. 2

1.2        Stacks. 2

1.2.1     Runtime Stacks. 2

1.2.2     Stack Access Notation. 2

1.3        Program Structure. 3

1.4        Examples. 3

1.4.1     Hello World Program.. 3

2.      Directives.. 3

2.1        Preprocessing.. 3

3.      Instructions.. 3

3.1        Nop. 4

3.2        Variable Declarations. 4

3.3        Control Flow... 4

3.4        Type Conversion.. 4

3.5        Direct Stack Access. 5

3.6        Arithmetic.. 5

3.7        Logic.. 6

3.8        String Concatenation.. 7

3.9        Console Input/Output.. 7

3.10       File Input/Output.. 7

3.11       Miscellaneous Instructions. 8

3.12       High-Level Language Error Reporting Support.. 8

 

 

 


1.     Introduction

Portia is a language and virtual machine implemented as an abstract stack machine.  It is named after the heroine in William Shakespeare’s The Merchant of Venice.

1.1    File Formats and Extensions

There are two types of Portia files: assembler and bytecode.  Assembler is an ASCII format and uses the extension PRA.  Bytecode is the binary format and uses the extension PRB.

1.2    Stacks

1.2.1   Runtime Stacks

The virtual machine runs four stacks concurrently.

 

Stack

Purpose

call-stack

recursive routine calling and returning

local-stack

holds local values during routine invocation

param-stack

holds routine parameters and routine return values

exp-stack

used by instructions to evaluate expressions

1.2.2   Stack Access Notation

This document uses a notation for stack access borrowed from Forth, a stack-based programming language.

 

               ( b a -- a b )

                   ^      ^

  top of stack before     |

                          |

          top of stack after

 

The left side of the double dashes shows the top of the stack prior to the instruction execution and after it.  If a variable has a type written next to it, attached by a colon, the variable must be of the type shown.  For example:

 

  ( x:int y:int -- z:bool )

 

This would mean that the instruction accepts two integers from the top of the stack and produces one boolean.

1.3    Program Structure

All programs must end with a stop instruction.

1.4    Examples

1.4.1   Hello World Program

# Hello World in Portia

push "Hello world!"

cout

push 10 #

asc     # output a newline character

cout    #

stop

 

 

2.     Directives

Directives are not actually instructions.  They give information to the virtual machine language processor.

2.1    Preprocessing

The preprocessor accepts two commands: file inclusion and comments.

 

$file.por

            Directly include the file “file.por” into the current file.

 

#this a comment

            Everything on a line following a “#” will be ignored.

 

:somewhere

            Defines a label at the point in the program called “somewhere”.

 

3.     Instructions

Instructions are executed directly by the virtual machine.

3.1    Nop

This instruction has no effect.

 

nop

3.2    Variable Declarations

These pseudo-instructions declare one or more variables and their type.

 

db var1 var2 ...

            Declare one or more bool variables.

di var1 var2 ...

            Declare one or more int variables.

dr var1 var2 ...

            Declare one or more rat variables.

ds var1 var2 ...

            Declare one or more str variables.

3.3    Control Flow

These instructions control the sequence of instructions executed.

 

jmp x:label

            Transfer control to the instruction after the label.

jt x:label

exp-stack: ( y:bool -- )

            Transfer control to the instruction after the label if the value on the stack is true.

jf x:label

     exp-stack: ( y:bool -- )

     Transfer control to the instruction after the label if x is false.

 

call x:label

     call-stack: ( -- y:label )

            Push the current location onto the call-stack, then transfer control to x.

ret

     call-stack: ( y:label -- )

            Pop a location off of the call-stack and transfer control to it.

stop

Terminate execution of the program.

3.4    Type Conversion

These instructions convert one type to another.

 

tob

     exp-stack: ( x:any -- y:bool )

            Convert value in x to bool and put in y.

toi

     exp-stack: ( x:any -- y:int )

            Convert value in x to int and put in y.

tor

     exp-stack: ( x:any -- y:rat )

            Convert value in x to rat and put in y.

tos

     exp-stack: ( x:any -- y:str )

            Convert value in x to str and put in y.

3.5    Direct Stack Access

copy

     exp-stack: ( x -- x x )

            Duplicate the item on the top of the stack.

swap

     exp-stack: ( x y -- y x )

            Swap the top two items on the stack.

pop y:t

popl y:t

popp y:t

     ( x:t -- )

Pop the top value off the stack and place it in the variable y.  The three versions of pop operate on the exp-stack, local-stack, and param-stack, respectively.

push x

pushl x

pushp x

     ( -- x )

Push the value of expression x onto the stack.  The three versions of push operate on the exp-stack, local-stack, and param-stack, respectively.

3.6    Arithmetic

addi

addr

exp-stack: ( x:type1 y:type2 -- z:type3 )

Add x and y, and put value in z.  The two versions of add require type3 to be int or rat, respectively.  The types of x and y can be int or rat.

subi

subr

exp-stack: ( x:type1 y:type2 -- z:type3 )

Subtract x and y, and put value in z.  The two versions of sub require type3 to be int or rat, respectively.  The types of x and y can be int or rat.

muli

mulr

exp-stack: ( x:type1 y:type2 -- z:type3 )

Multiply x and y, and put value in z.  The two versions of mul require type3 to be int or rat, respectively.  The types of x and y can be int or rat.

divi

divr

exp-stack: ( x:type1 y:type2 -- z:type3 )

Divide x and y, and put value in z.  The two versions of div require type3 to be int or rat, respectively.  The types of x and y can be int or rat.

powi

powr

exp-stack: ( x:type1 y:type2 -- z:type3 )

Raise x to the power of y, and put value in z.  The two versions of pow require type3 to be int or rat, respectively.  The types of x and y can be int or rat.

modi

modr

exp-stack: ( x:int y:int -- z:type )

Divide x by y, and put remainder in z.  The two versions of mod require type to be int or rat, respectively.

neg

exp-stack: ( x:t -- y:t )

Negate x and put the result in y.  The type t of x and y are the same and must be a number type (int or rat).

3.7    Logic

eq

exp-stack: ( x:type1 y:type2 -- z:bool )

Check if x and y are equal, and put boolean result in z.  The types of x and y can both be numbers, both be bool, or both be str.

neq

exp-stack: ( x:type1 y:type2 -- z:bool )

Check if x and y are not equal, and put boolean result in z.  The types of x and y can both be numbers, both be bool, or both be str.

lt

exp-stack: ( x:type1 y:type2 -- z:bool )

Check if x is less than y, and put boolean result in z.  The types of x and y must both be numbers.

lteq

exp-stack: ( x:type1 y:type2 -- z:bool )

Check if x is less than or equal to y, and put boolean result in z.  The types of x and y must both be numbers.

gt

exp-stack: ( x:type1 y:type2 -- z:bool )

Check if x is greater than y, and put boolean result in z.  The types of x and y must both be numbers.

gteq

exp-stack: ( x:type1 y:type2 -- z:bool )

Check if x is greater than or equal to y, and put boolean result in z.  The types of x and y must both be numbers.

or

exp-stack: ( x:bool y:bool -- z:bool )

Perform logical or on x and y, and put boolean result in z.

and

exp-stack: ( x:bool y:bool -- z:bool )

Perform logical and on x and y, and put boolean result in z.

not

exp-stack: ( x:bool -- y:bool )

Perform logical not on x, and put result in y.

3.8    String Concatenation

cat

exp-stack: ( x:str y:str -- z:str )

Append y to the end of x and put resulting string in z.

3.9    Console Input/Output

cout

exp-stack: ( x -- )

Print x on the console.

cin

exp-stack: ( -- x:str )

Get a string from the user and put it in x.

3.10   File Input/Output

The following file input/output instructions read to and write from text files.

 

fio_or filename:str

     exp-stack: ( -- handle:int )

            Open a file for reading called filename and put a file handle integer in handle.

fio_ow filename:str

     exp-stack: ( -- handle:int )

            Open a file for writing called filename and put a file handle integer in handle.

fio_c handle:int

     exp-stack: ( -- )

            Close the file designated by handle.

fio_eof handle:int

     exp-stack: ( -- reached:bool )

Check if the end-of-file has been reached in the file designated by handle.  If it has, put “true” in reached, otherwise, put “false” in reached.

fio_r handle:int

     exp-stack: ( -- input:str )

Read a line of text from the file designated by handle into input.

fio_w handle:int

     exp-stack: ( output:str -- )

Write text from output to the file designated by handle.

3.11   Miscellaneous Instructions

asc

exp-stack: ( x:int -- y:str )

Get the character corresponding to the ASCII code in x and put it in y.

rand

exp-stack: ( -- x:int )

Generate a random integer and put it in x.  The value is in the range 0 to at least 32768, inclusive.  Best used in conjunction with mod.

3.12   High-Level Language Error Reporting Support

The following instructions are generated by the compiler for high-level languages (HLLs), allowing the Portia virtual machine to report the location of runtime errors in the original HLL source file.

 

dbgon

Activates HLL error reporting.  This should only appear once in the input file and at the very beginning.

dbgfile string_literal

Sets the error reporting file to the file specified by the string literal.

dbgline int_literal

Sets the error reporting line number to the number specified by the integer literal.