courses/compiler/chapter_2.md
Simon From Jakobsen 44aae17334 init
2024-08-22 13:04:41 +00:00

3.6 KiB

2 Specifying a language

You can skip this chapter and come back to it, if you need.

The language will at first consist of these features.

  • Literals
  • Expressions
  • Variables
  • Blocks
  • If-conditions
  • Loops
  • Function calls
  • Function definitions

2.1 Literals

Integers (ints) are numbers without decimal point.

Strings are text enclosed in double-quotes " ". Backslash \ can be used to escape " and invoke specialt characters \n and \t for newline and tab characters.

Booleans (bools) represent logical true and false and are the symbols true and false.

Null represents a non-value (null value) and is the symbol null.

Examples:

0
123
"hello"
"{ \"key\": 123 }"
true
false
null

2.2 Expressions

I'll be reusing the prefix notation expressions from chapter 1. These are also called S-expressions.

I'll be using logical expressions (or, and and not), comparison expressions (==, !=, < and >), arithmetic expressions (+, -, *, /) and group expressions ((...)).

The grammer, meaning the rules for the structure of the code, is the following:

expr ->
    ...
    |   "or" expr expr
    |   "and" expr expr
    |   "not" expr
    |   "==" expr expr
    |   "!=" expr expr
    |   "<" expr expr
    |   ">" expr expr
    |   "+" expr expr
    |   "-" expr expr
    |   "*" expr expr
    |   "/" expr expr
    |   "(" expr ")"
    ...
    |   literal

Notice not only has 1 operand.

Examples:

+ 1 * 2 3

+ + + 1 2 3 4

* 3 (* 3 3)

2.3 Variables

A variable is a storage container for a value.

A variable is defined using a let-statement. A variable is used by refering to its name. A variable can be reassigned after definition.

Variables are block-scoped, more on this later.

Grammar:

let ->  "let" ident "=" expr ";"

assign -> ident "=" expr ";"

expr ->
    ...
    | ident
    ...

Examples:

let a = 5;

a = 10;

+ a 10

2.4 Blocks

A block is code enclosed in curly-braces ({ and }). They can be used as both statements and expressions. Single-line statements in a block need semicolon (;) at the end. Expressions can be used as statements.

If the last entry in a block is an expression and the semicolon is omitted, the block as a whole yields that value.

Grammar:

block -> "{" statements expr:? "}"

expr ->
    ...
    | block
    ...

Examples:

{}

{
    let a = 5;
}

let a = {
    let b = 5;
    + b 5
};

2.5 If-statements

An if-statement has a condition and a block it runs, if the condition evaluates to true ("truthy"), and an optional else-block, if it the condition evaluates to false.

Grammar:

if  ->  "if" expr block ("else" block):?

expr ->
    ...
    | if
    ...

I've added if to expr, because, in addition to a statement, I want to be able to use if as an expression just like blocks.

Examples:

let a = 5;
if == b 5 {
    a = 5;
}

let value = if > a b { c } else { d };

2.6 Loops

loop-statements are blocks that run continually (from top to bottom, then from the top again) until a break-statement is evaluated.

Loops can also be expressions, as a value can be supplied when breaking.

Grammar:

loop    ->  "loop" block

break   ->  "break" expr:? ";"

expr ->
    ...
    | loop
    ...

Examples:

let i = 0;
let v = 1;
loop {
    if not < i 10 {
        break;
    }
    v = * v 2;
    i = + i 1;
}

let v = loop {
    break 5;
};

2.7 Function calls

Grammar:

expr ->
    ...
    | expr "(" args ")"
    ...

Examples:

let a = pow(2, 3);

exit();

2.8 Function definition

Grammar:

fn      ->  "fn" ident "(" params ")" block

return  ->  "return" expr:? ";"