Zinc Reference Manual

Marc Kerbiquet

Abstract

Zinc is a low level programming language to write small and fast programs.

Chapter 1. Introduction

Zinc is a low level programming language to write small and fast programs. It is a low level language between assembler, C and C++ with a syntax somewhat similar to Ruby.

Important Notice / Disclaimer

This programming language is still experimental, it contains some inconsistencies and missing features that are subject to change in the future. It should not be used for something else than the text editor 'Code Browser'. This documentation is provided only to understand or edit the source code of Code Browser.

Chapter 2. Lexical Conventions

General

  • New lines are relevants and are equivalents to semicolons. The following lines:

    instr1
    instr2
    instr3
    

    are equivalents to:

    instr1 ; instr2 ; instr3
    

    New lines are ignored after some characters:

    ( , : = + - * ...
    
  • Empty lines are ignored

Comments

Single line comments starts with two slashes.

// this is a comment

Multiple line comments start with a /* and finish with */. Nested comments are not permited.

/* 
  This is another comment
  on several lines 
*/

Identifiers

An identifier is defined as follow:

  • A word is a sequence of letters, underscores or digits and cannot start with a digit. Words are case sensitive.

    abc
    abc12
    ab1c2d
    
  • A number is a sequence of digits.

    1
    23
    
  • A blank is a space or a tabulation

  • An identifier is a sequence of words and numbers separated by blanks. The number of blanks is not relevant. The first item of an identifier cannot be a number or a reserved keyword.

    var1
    var 1
    yet another variable
    

Keywords

List of reserved keywords:

def
equ
func
struct
union
enum
typedef
sizeof
public
private
const
import
if
elsif
while
switch
case
else
end
return
repeat

Special Identifiers

The language has some builtin identifiers that are not reserved word such as nil, true and false. It is possible to use them in different identifiers or with different signature:

true 1  // a valid identifier
nil (-> void) // a valid function

Keywords

Operators

+	-	*	/	%	<<	>>
==	<>	<	>	<=	>=
&	|	^	&&	||
=	+=	-=	*=	/=	%=	<<=	>>=
&=	|=	^=	~!	-!
~	++	--

Chapter 3. Types

Types are not defined in the same namespace as expressions, so types are not reserved names.

There can be inheritance between types, for instance:

  • a structure can inherit from another structure
  • a signed integer inherits from an unsigned integer

Basic Types

Table 3.1. Basic Types

NameDescription
byteunsigned 8 bit integer
wordunsigned 16 bit integer
dwordunsigned 32 bit integer
octetsigned 8 bit integer
shortsigned 16 bit integer
intsigned 32 bit integer
boolboolean type
charcharacter type
voidspecial type to express 'nothing'

Pointers

Pointer to a type:

-> type

Pointers preserves inheritance: if t2 inherits from t1, -> t2 intherits from -> t1.

Arrays

[n] type

n is a positive integer.

  • [*] type is an alias for [0] type.
  • [] type is an alias for -> [*] type, i.e. a pointer to an undefined size array of type items.

Examples:

[10] int	// an array of 10 integers
[10] [20] int	// a two dimension array of integer
[] char		// a pointer to an array of character 

[n2] t2 inherits from [n1] t1 if and only if n1=n2 and t2 inherits from t1.

Function Pointers

{type1, type2, ...} return-type

This type is a pointer, but the -> is implicit.

Examples:

{int, int} int
{int} void

// A function without argument:
{} int

Anonymous Structures and Unions

Anonymous structures (and unions) are defined in the same way as named structures but wihout the name:

def origin: 
  struct
    x: int
    y: int
  end

Attributes of anonymous structures are always private.

Anonymous Enums

Anonymous enums are defined in the same way as regular enums but wihout the name:

def category: 
  enum 
    rock
    pop
    folk
    classic
  end

Values of anonymous enums are always private.

Named Types

A named type is an identifier that can be

  • a basic type
  • the name of a structure
  • the name of an union
  • the name of an enum
  • an alias to another type (typedef)

Chapter 4. Expressions

Literals

Numbers

  • Decimals: (+|-)?[0-9]+
  • Hexadecimals: (+|-)?0x[0-9a-fA-F]+

A literal number is 32 bit signed. A cast can be used to get a different type:

123:byte  // unsigned byte 
12345:short  // signed short
0x5f:byte  // unsigned byte

Strings

"aaaa"

Table 4.1. String Escape Characters

CharacterDescription
\aBell (7)
\bBackspace (8)
\fForm Feed (12)
\nLine Feed (10)
\rCariage Return (13)
\tTab (9)
\vVertical Tab (11)
\wWhitespace (32)
\"double quotes

If two literal strings are adjacents, they can be concatened: "abc" "def" is same as "abcdef". It can be useful for long string, since you can join two lines with the '\' character:

"abc" \
"def"

Characters

  • $c for regular characters
  • \c for escape characters, one of:

    Table 4.2. Escape Characters

    CharacterDescription
    \aBell (7)
    \bBackspace (8)
    \fForm Feed (12)
    \nLine Feed (10)
    \rCariage Return (13)
    \tTab (9)
    \vVertical Tab (11)
    \wWhitespace (32)
  • \nn for numeric characters

Booleans

  • true
  • false

Initializers

const <pointer type> (<list of arguments>)

<pointer type> is a either a pointer to an array or a pointer to a structure. arguments must match the type. Each argument must be a constant.

Function References

^ <function name> [(<list of types>)]

<function name> is the name of the function followed by the types of arguments between parenthesis. Do not put parenthesis if the function has no parameter.

Null Value Pointer

nil

Nil is a pointer with value to 0 and its type is a special pointer type that matches with all pointer types, i.e. this value can be use anywhere a pointer value is expected.

Operators

Arithmetic Operators

Unary:

+ -

Binary:

+ - * / %

Comparators

== <> < > <= >=

Bitwise Logical Operators

Table 4.3. Bitwise Logical Operators

OperatorDescription
&and
|or
^exclusive or
<<left shift
>>right shift
&&and, eval 2nd expr if and only if 1st is true
||or, eval 2nd expr if and only if 1st is false

Increment and Decrement Operators

++
--

If suffixed, the expression evaluates to value before increment or decrement. Otherwise it evaluates to value after the operation.

Assignment Operators

left = right

Assigns the right expression to the left expression.

left := fn (arg1, ...)

Special operator: the right expression must be a function with 'returned argument', the left expression must be a pointer that is passed to the function as the returned argument.

left OP= right

is equivalent to:

left = left OP right

Conditional Operator

boolean exp -> e1, e2

If the boolean expression is evaluated to true, the expression is evaluated to e1, e2 otherwise.

Indirection Operator

e[]

e is an expression of type pointer

Index Operator

e[n]

  • e is a pointer to an array
  • n is an integer

e[] is an alias for e[0]

Notes:

  • e can also be of another type if the operator is redefined.
  • the operator can take several argument of any type when redefined:
    e[e1, e2, ...]
    

Function Call Operator

e {e1, e2, ...}

  • e is a pointer to a function
  • e1, e2, ... are the arguments

When there is no argument:

e {}

Type Conversion

e : type

All operators except =, :=, : and {} are functions that can be redefined. The operators can be redefined as functions as well as equates.

Function Calls

Functions, equates and iterators without arguments:

f

Functions, equates and iterators with arguments:

f (arg1, arg2, ...)

Iterator with block without parameters:

f (arg1, arg2, ...) ?
  instr1
  instr2
  ...
end

Iterator with block with parameters:

f (arg1, arg2, ...) ? x1, x2, ...
  instr1
  instr2
  ...
end

Builtin Functions

is nil (p)

Returns true if p is nil. p is a pointer.

not nil (p)

Returns true if p is not nil. p is a pointer.

Chapter 5. Statements

Table of Contents

If
While
Repeat
Switch

If

if cond1
  ...
elsif cond2
  ...
elsif ...
  ...
else
  ...
end

Where:

  • cond1, cond2 are boolean expressions.
  • elsif and else statements are optionals

While

while cond
  ...
end

Repeat the block as long as the boolean expression cond evaluates to true. The break statement can interrupt the loop.

Repeat

repeat
  ...
end

A synonym for while true, and endless loop can that only be interrupted by a break.

Switch

switch e
case c1
  ...
case c2
  ...
case ...
  ...
else
  ...
end

e is an integer or character expression. c1 and c2 are constant integers or characters. The else statement is optional.

Chapter 6. Declarations

General

Order of declarations

The order of declarations is not important except:

  • local variables must be declared before use
  • when size of a type must be known Ok: struct aa x: bb // pointer: size known (4 bytes) end struct bb ... end Error: struct aa x: local bb // size of bb must be known end struct bb ... end

Polymorphism

Each declaration must have a unique name+signature, but the name itself has not to be unique.

Exposition

Declaration are public or private: a private declaration is not visible outside its module (currently, a module is equivalent to a source file), a public delcaration is visible when its module is imported.

Variables

Variables are locals or globals. A variable is a value that can be stored in a machine register.

Define an Uninitialized Variable

def name : type

if the type is a structure or an array, a variable is always a constant pointer to the element.

Define and Initialize a Variable

def name = e1

The type of the variable if the type of the expression.

Define Constant References
def name := fn (e1, e2, ...)

name is a constant reference to a local structure initialized with the function. The type is the type of the returned argument of the function.

def name := "a string"
def name := const type (...)

Constants are not lvalues: they cannot be modified. They are constant effective address evaluable by the compiler and are not stored in registers.

Difference between = and :=

def name1 = "a string"
def name2 := "a string"

name1 is a variable initialized to a pointer to the string "a string". name2 is a constant pointer to "a string".

Functions

Define a function:

func name (arg1: t1, arg2: t2, ...) [: return-type]
  ...
end

The return type is optional. In fact it is required only when there is a circular reference with the function. This can happen when

  • the function is recursively called.
  • when the function or a callee have a reference to it.

Types of arguments cannot be structures or array, they must be pointers or basic types, i.e. values that can be stored in registers.

To return a value or simply return from the function, just use

return [expr]

There is an alternative syntax to define functions:

func name (arg1: t1, arg2: t2, ...) -> (return-arg: return-type)
  ...
end

It must be a void function, the return-arg behaves like other arguments except that its type must be a pointer to a structure or an array. This kind of function differs by its calling method:

  • x := name (arg1, arg2, ...)
    
    x is passed as the returned argument.
  • def y := name (arg1, arg2, ...)
    
    A structure or an array is created with the constant reference y pointing to it. then y is passed as the returned argument.
  • name (arg1, arg2, ...)
    
    A structure or an array is created and its effective address is passed as the returned argument and the expression evaluates to it.

Redefinition of Operators

There is special function names to redefine operators

Table 6.1. Operator Names

NameOperation
@add+
@sub-
@mul*
@div/
@mod%
@shl<<
@shr>>
@equal==
@not equal<>
@less or equal<=
@less than<
@greater or equal>=
@greater than>
@and&
@xor^
@or |
@andand&&
@oror||
@assign add+=
@assign sub-=
@assign mul*=
@assign div/=
@assign mod%=
@assign shl<<=
@assign shr>>=
@assign and&=
@assign or|=
@assign xor^=
@assign not~!
@assign neg-!
@not~
@preincprefixed ++
@predecprefixed --
@postincpostfixed ++
@postdecpostfixed --
@atindexed access

Equates

Equates are for macro expansion. There is two kind of equates:

  1. simple expression substitution
  2. iterators

Simple Expression Substitution

equ name (arg1: t1, arg2: t2, ...) = expr

expr is the expression that will replace the equate call.

expr is fully analysed when the equate is defined:

  • no need of parenthesis as in C
  • function calls in expr are frozen, no matter what the real types of arguments are.
  • epxr can use private definition even if the equate is public.

Arguments are expanded as is in the expression, if an argument is a function call, the call will be performed for each occurrence of the argument in the expression. If an argument is not used in the expression, it won't be evaluated. Equates must be used carefully especially when switching a function to an equate or vice-versa.

If an expression passed to the equate is an lvalue, the associate argument becomes an lvalue.

Iterators

This special kind of equate is called iterator because its main use is for iterators but it can be used for anything else such as allocating and freeing a resource in one step.

equ name (arg1: t1, arg2: t2, ...)
  ...
end

There can be zero, one or more occurrences of yield in the body of the iterator.

  • 0 yield: the iterator does not have a block
    equ print twice (s: string)
      puts (s)
      puts (s)
    end
    
    print twice ("hello world")
    
  • 1 or more yield: the iterator has a block with or without parameters. If there is more than one yield, all must have a compatible signature.
    equ loop (n: int)
      def i = 1
      while i <= n
        yield (i)
        i += 1
      end
    end
    
    loop (10) ? j
      printf("%d\n", j)
    end
    

Iterators are still limited now: it is not possible to break an iteration.

Structures and Unions

Define a structure:

struct name [:parent name]
  attr1: t1
  attr2: t2
  public
    attr3: t3
    attr4: t4
  end
  private attr5: t5
  public attr6: t6
end

This creates a structure named local name and an alias named name that is a pointer to this structure.

For each attribute attr of the structure name, a declaration is created to read and modifiy it:

attr (t: name)

When the exposition of an attribute is not specified, it inherits the exposition of the structure.

Inheritance

A structure can inherit from another structure, all attributes are inherited: it is equivalent to add them at the beginning. A pointer to a structure is also considered as a pointer to its parent structure.

A pointer to a structure can be converted to a pointer to its parent structure using super(x).

Unions

An union is like a structure except that all attributes overlaps (they all start at offset 0). Just replace struct by union.

Enumerations

Define an enumeration

enum name
  item1 [= value1]
  item2 [= value2]
  ...
end

An enumeration is an integer.

Each item can have a value assigned to it. If the value is not specified, it gets the value of its predecessor plus one or zero for the first item.

Type Aliases (typedef)

Define a type alias

typedef name = type

Imports

To import public declarations of another module:

import "module-name"

The name of the module is the path relative to the include path plus the filename without the extension (.zc).

Circular imports is not permitted: modules cannot be inter-dependents.