This section defines lexical details of the Levi language.
while1 is an identifier but while is not.
Examples of legal string literals:
"" "&!88" "use \n to denote a newline character" "use \" to for a quote and \\ for a backslash"
"unterminated "also unterminated \" "backslash followed by space: \ is not allowed" "bad escaped character: \a AND not terminated
=:,+-==>>>>=[<<\\(-o-)//{<<=(!!=--++]});.../*
# this is a comment # and so is # this # and so is # this %$!#
The scanner should recognize and ignore comments (there is no COMMENT token).
For the most part, the token to produce should be self-explanatory. For
example, the
+
symbol should produce the
CROSS
token, the
-
symbol should produce the
DASH
token, etc. The set of tokens can be found in
frontend.hh
or in the switch in tokens.cpp. The LCURLY token refers to a left curly brace,
{.
the RCURLY refers to a right curly brace,
}.
The lexical structure of Levi is fairly straightforward, and largely similar to C. There are a few notable details, some of which are departures from C:
\\(-o-)// produces the THRASH token.... produces the SINK token.>> and << produce INPUT and OUTPUT, respectively.thrash,
and
sink,
are keywords of the language. They produce the
THRASH,
and
SINK,
tokens, respectively.file produces the FILE token&& and || are NOT in the language . Instead "logical and" is represented by the string and and "logical or" is represented by the string or.
This section described the syntax of the Levi language.
While the canonical reference for Levi syntax is its context-free grammar, there are a couple of "standout" points which deserve special attention for their deviation from C:
myfn : (a:int, b:int, c:int) bool { }
bool myFunction(int a, int b, int c) { }
i:int; i = 4;
is not a legal program, but
i:int;
fn : () void {
i = 4;
}
is legal.
file.
ofile << "hello";
or
ifile >> var;
is legal.
/*********************************************************************
Grammar for programs in the Levi language
********************************************************************/
program ::= globals
globals ::= globals decl
| /* epsilon */
decl ::= varDecl SEMICOL
| fnDecl
varDecl ::= name COLON type
| name COLON type ASSIGN initializer
type ::= datatype
| IMMUTABLE datatype
datatype ::= primtype LBRACKET INTLITERAL RBRACKET
| primtype
primType ::= INT
| BOOL
| FILE
| VOID
fnDecl ::= name COLON LPAREN maybeformals RPAREN type LCURLY stmtList RCURLY
maybeformals ::= formalsList
| /* epsilon */
formalsList ::= formalDecl
| formalsList COMMA formalDecl
formalDecl ::= name COLON type
stmtList ::= stmtList stmt SEMICOL
| stmtList blockStmt
| /* epsilon */
blockStmt ::= WHILE LPAREN exp RPAREN LCURLY stmtList RCURLY
| IF LPAREN exp RPAREN LCURLY stmtList RCURLY
| IF LPAREN exp RPAREN LCURLY stmtList RCURLY ELSE LCURLY stmtList RCURLY
stmt ::= varDecl
| loc ASSIGN exp
| callExp
| loc POSTDEC
| loc POSTINC
| loc OUTPUT exp
| loc INPUT loc
| SINK name
| RETURN exp
| RETURN
exp ::= exp DASH exp
| exp CROSS exp
| exp STAR exp
| exp SLASH exp
| exp AND exp
| exp OR exp
| exp EQUALS exp
| exp NOTEQUALS exp
| exp GREATER exp
| exp GREATEREQ exp
| exp LESS exp
| exp LESSEQ exp
| NOT exp
| DASH term
| term
callExp ::= loc LPAREN RPAREN // fn call with no args
| loc LPAREN actualsList RPAREN // with args
actualsList ::= exp
| actualsList COMMA exp
term ::= loc
| literal
| THRASH
| LPAREN exp RPAREN
| callExp
literal : INTLITERAL
| STRINGLITERAL
| TRUE
| FALSE
litList : literal
| literal COMMA litList
initializer : literal
| LBRACKET litList RBRACKET
loc ::= name
| loc LBRACKET exp RBRACKET
name ::= ID
This section defines details of the Levi type system.
Any type is promotable to itself.
OperandsThe following shows the atomic operands and the types that they are assigned:
intboolThe operators in the language are divided into the following categories:
[ ])=)The type rules of the language are as follows:
logical operators and conditions are legal if and only if:
The result type is bool in legal cases, ERROR otherwise.
In all illegal cases, the result type is ERROR.
relational operations are legal if and only if:
intThe result type is bool in legal cases, ERROR otherwise.
equality operations are legal if and only if:
The result type is bool in legal cases, ERROR otherwise.
assignment operations are legal if and only if:
It is LEGAL to assign arrays of the same base type but different lengths regardless if the LHS or RHS is bigger
The result type is that of the LHS operand in legal cases, ERROR otherwise.
in >> operations are legal if and only if:
int or bool
.
out << operations are legal if and only if:
intboolstringindexing operations are legal if and only if:
intThe result type is the base type of the array in legal cases, and ERROR otherwise.
function calls are legal if and only if:
If the identifier is not a function name, the result type is ERROR. Otherwise, it is the return type of the function even if the arguments are ill-typed.
function returns: The follow rules hold for function returns:
void function
may not have a value.
void
function must have a value.
It is LEGAL for a non-void function to skip a return statement. For example, this code is ok:
f : () int {
//I should return an int, but I don't
}