Change name from binding to precedence, add readme info

This commit is contained in:
Krzosa Karol
2024-04-14 10:33:09 +02:00
parent 44eb8be1db
commit c99f669c0e
3 changed files with 107 additions and 71 deletions

View File

@@ -83,11 +83,9 @@ You only need to compile the build tool once. Afterwards just call `./bld.exe`.
## Further plans
My priority is to improve the C user API, harden the compiler, accommodate things that I didn't foresee and stuff like that.
Sometime in the future I want to implement a bytecode backend so that the language can be used like Lua as a nice scripting language.
I'm also considering the addition of overloaded procedures because it would greatly aid in writing macros.
- **My priority is to improve the C user API, harden the compiler, accommodate things that I didn't foresee and stuff like that.**
- I want to implement a bytecode backend (in the future) so that the language can be used like Lua.
- New features are of second priority unless they are small and important but additionally I'm considering the addition of overloaded procedures because it would greatly aid in writing macros.
# Language overview
@@ -438,6 +436,55 @@ test :: proc() {
}
```
## Arithmetic operators
``` odin
arithmetic_operators :: proc() {
add := 1 + 2;
sub := 1 - 2;
mul := 1 * 2;
div := 1 / 2;
mod := 1 % 2;
and := 1 && 2;
or := 1 || 2;
equals := 1 == 2;
not_equals := 1 != 2;
greater_then := 1 > 2;
greater_then_or_equal := 1 >= 2;
lesser_then := 1 < 2;
lesser_then_or_equal := 1 <= 2;
left_shift := 1 >> 2;
right_shift := 1 << 2;
bit_or := 1 | 2;
bit_and := 1 & 2;
bit_xor := 1 ^ 2;
not := !1;
negate := ~1;
}
```
## Arithmetic assignment operators
``` odin
arithmetic_assign_operators :: proc() {
a := 1;
a /= 1;
a *= 1;
a %= 1;
a -= 1;
a += 1;
a &= 1;
a |= 1;
a ^= 1;
a <<= 1;
a >>= 1;
}
```
## Defer statement
A defer statement allows to postpone a certain action to the end of scope. For example - you might allocate memory and use defer just bellow your allocation to free the memory. This free will be deferred, it will happen a bit later.

View File

@@ -781,13 +781,13 @@ typedef enum {
typedef struct {
int left;
int right;
} LC_BindingPower;
} LC_Precedence;
typedef enum {
LC_Binding_Prefix,
LC_Binding_Infix,
LC_Binding_Postfix,
} LC_Binding;
LC_PrecedenceKind_Prefix,
LC_PrecedenceKind_Infix,
LC_PrecedenceKind_Postfix,
} LC_PrecedenceKind;
typedef enum {
LC_CmpRes_LT,
@@ -828,12 +828,6 @@ struct LC_FileIter {
X(struct) \
X(union) \
X(addptr) \
X(and) \
X(or) \
X(bit_and) \
X(bit_or) \
X(bit_xor) \
X(not ) \
X(true) \
X(false)
@@ -1141,38 +1135,37 @@ LC_FUNCTION LC_Type *LC_StripPointer(LC_Type *type);
LC_FUNCTION LC_AST *LC_ParseFile(LC_AST *package, char *filename, char *content, int line);
LC_FUNCTION LC_AST *LC_ParseTokens(LC_AST *package, LC_Lex *x);
LC_FUNCTION LC_Parser LC_MakeParser(LC_Lex *x);
LC_FUNCTION LC_Parser *LC_MakeParserQuick(char *str);
LC_FUNCTION LC_Token *LC_Next(void);
LC_FUNCTION LC_Token *LC_Get(void);
LC_FUNCTION LC_Token *LC_GetI(int i);
LC_FUNCTION LC_Token *LC_Is(LC_TokenKind kind);
LC_FUNCTION LC_Token *LC_IsKeyword(LC_Intern intern);
LC_FUNCTION LC_Token *LC_Match(LC_TokenKind kind);
LC_FUNCTION LC_Token *LC_MatchKeyword(LC_Intern intern);
LC_FUNCTION LC_BindingPower LC_MakeBP(int left, int right);
LC_FUNCTION LC_BindingPower LC_GetBindingPower(LC_Binding binding, LC_TokenKind kind);
LC_FUNCTION LC_AST *LC_ParseExprEx(int min_bp);
LC_FUNCTION LC_AST *LC_ParseCompo(LC_Token *pos, LC_AST *left);
LC_FUNCTION LC_AST *LC_ParseExpr(void);
LC_FUNCTION LC_AST *LC_ParseProcType(LC_Token *pos);
LC_FUNCTION LC_AST *LC_ParseType(void);
LC_FUNCTION LC_AST *LC_ParseForStmt(LC_Token *pos);
LC_FUNCTION LC_AST *LC_ParseSwitchStmt(LC_Token *pos);
LC_FUNCTION LC_AST *LC_ParseStmt(bool check_semicolon);
LC_FUNCTION LC_AST *LC_ParseStmtBlock(int flags);
LC_FUNCTION LC_AST *LC_ParseProcDecl(LC_Token *name);
LC_FUNCTION LC_AST *LC_ParseStruct(LC_ASTKind kind, LC_Token *ident);
LC_FUNCTION LC_AST *LC_ParseTypedef(LC_Token *ident);
LC_FUNCTION LC_AST *LC_CreateNote(LC_Token *pos, LC_Intern ident);
LC_FUNCTION LC_AST *LC_ParseNote(void);
LC_FUNCTION LC_AST *LC_ParseNotes(void);
LC_FUNCTION bool LC_ResolveBuildIf(LC_AST *build_if);
LC_FUNCTION LC_AST *LC_ParseImport(void);
LC_FUNCTION LC_AST *LC_ParseDecl(LC_AST *file);
LC_FUNCTION bool LC_EatUntilNextValidDecl(void);
LC_FUNCTION bool LC_ParseHashBuildOn(LC_AST *n);
LC_FUNCTION LC_AST *LC_ParseFileEx(LC_AST *package);
LC_FUNCTION LC_Parser LC_MakeParser(LC_Lex *x);
LC_FUNCTION LC_Parser *LC_MakeParserQuick(char *str);
LC_FUNCTION LC_Token *LC_Next(void);
LC_FUNCTION LC_Token *LC_Get(void);
LC_FUNCTION LC_Token *LC_GetI(int i);
LC_FUNCTION LC_Token *LC_Is(LC_TokenKind kind);
LC_FUNCTION LC_Token *LC_IsKeyword(LC_Intern intern);
LC_FUNCTION LC_Token *LC_Match(LC_TokenKind kind);
LC_FUNCTION LC_Token *LC_MatchKeyword(LC_Intern intern);
LC_FUNCTION LC_Precedence LC_GetPrecedence(LC_PrecedenceKind binding, LC_TokenKind kind);
LC_FUNCTION LC_AST *LC_ParseExprEx(int min_bp);
LC_FUNCTION LC_AST *LC_ParseCompo(LC_Token *pos, LC_AST *left);
LC_FUNCTION LC_AST *LC_ParseExpr(void);
LC_FUNCTION LC_AST *LC_ParseProcType(LC_Token *pos);
LC_FUNCTION LC_AST *LC_ParseType(void);
LC_FUNCTION LC_AST *LC_ParseForStmt(LC_Token *pos);
LC_FUNCTION LC_AST *LC_ParseSwitchStmt(LC_Token *pos);
LC_FUNCTION LC_AST *LC_ParseStmt(bool check_semicolon);
LC_FUNCTION LC_AST *LC_ParseStmtBlock(int flags);
LC_FUNCTION LC_AST *LC_ParseProcDecl(LC_Token *name);
LC_FUNCTION LC_AST *LC_ParseStruct(LC_ASTKind kind, LC_Token *ident);
LC_FUNCTION LC_AST *LC_ParseTypedef(LC_Token *ident);
LC_FUNCTION LC_AST *LC_CreateNote(LC_Token *pos, LC_Intern ident);
LC_FUNCTION LC_AST *LC_ParseNote(void);
LC_FUNCTION LC_AST *LC_ParseNotes(void);
LC_FUNCTION bool LC_ResolveBuildIf(LC_AST *build_if);
LC_FUNCTION LC_AST *LC_ParseImport(void);
LC_FUNCTION LC_AST *LC_ParseDecl(LC_AST *file);
LC_FUNCTION bool LC_EatUntilNextValidDecl(void);
LC_FUNCTION bool LC_ParseHashBuildOn(LC_AST *n);
LC_FUNCTION LC_AST *LC_ParseFileEx(LC_AST *package);
//
// Resolution functions

View File

@@ -102,39 +102,35 @@ LC_FUNCTION LC_Token *LC_MatchKeyword(LC_Intern intern) {
// Pratt expression parser
// Based on this really good article: https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html
// clang-format off
LC_FUNCTION LC_BindingPower LC_MakeBP(int left, int right) {
LC_BindingPower result = {left, right};
return result;
}
LC_FUNCTION LC_BindingPower LC_GetBindingPower(LC_Binding binding, LC_TokenKind kind) {
if (binding == LC_Binding_Prefix) goto Prefix;
if (binding == LC_Binding_Infix) goto Infix;
if (binding == LC_Binding_Postfix) goto Postfix;
LC_FUNCTION LC_Precedence LC_MakePrecedence(int left, int right) { return {left, right}; }
LC_FUNCTION LC_Precedence LC_GetPrecedence(LC_PrecedenceKind p, LC_TokenKind kind) {
if (p == LC_PrecedenceKind_Prefix) goto Prefix;
if (p == LC_PrecedenceKind_Infix) goto Infix;
if (p == LC_PrecedenceKind_Postfix) goto Postfix;
LC_ASSERT(NULL, !"invalid codepath");
Prefix:
switch (kind) {
case LC_TokenKind_OpenBracket: return LC_MakeBP(-2, 22);
case LC_TokenKind_OpenBracket: return LC_MakePrecedence(-2, 22);
case LC_TokenKind_Mul: case LC_TokenKind_BitAnd: case LC_TokenKind_Keyword: case LC_TokenKind_OpenParen:
case LC_TokenKind_Sub: case LC_TokenKind_Add: case LC_TokenKind_Neg: case LC_TokenKind_Not: case LC_TokenKind_OpenBrace: return LC_MakeBP(-2, 20);
default: return LC_MakeBP(-1, -1);
case LC_TokenKind_Sub: case LC_TokenKind_Add: case LC_TokenKind_Neg: case LC_TokenKind_Not: case LC_TokenKind_OpenBrace: return LC_MakePrecedence(-2, 20);
default: return LC_MakePrecedence(-1, -1);
}
Infix:
switch (kind) {
case LC_TokenKind_Or: return LC_MakeBP(9, 10);
case LC_TokenKind_And: return LC_MakeBP(11, 12);
case LC_TokenKind_Or: return LC_MakePrecedence(9, 10);
case LC_TokenKind_And: return LC_MakePrecedence(11, 12);
case LC_TokenKind_Equals: case LC_TokenKind_NotEquals: case LC_TokenKind_GreaterThen:
case LC_TokenKind_GreaterThenEq: case LC_TokenKind_LesserThen: case LC_TokenKind_LesserThenEq: return LC_MakeBP(13, 14);
case LC_TokenKind_Sub: case LC_TokenKind_Add: case LC_TokenKind_BitOr: case LC_TokenKind_BitXor: return LC_MakeBP(15, 16);
case LC_TokenKind_GreaterThenEq: case LC_TokenKind_LesserThen: case LC_TokenKind_LesserThenEq: return LC_MakePrecedence(13, 14);
case LC_TokenKind_Sub: case LC_TokenKind_Add: case LC_TokenKind_BitOr: case LC_TokenKind_BitXor: return LC_MakePrecedence(15, 16);
case LC_TokenKind_RightShift: case LC_TokenKind_LeftShift: case LC_TokenKind_BitAnd:
case LC_TokenKind_Mul: case LC_TokenKind_Div: case LC_TokenKind_Mod: return LC_MakeBP(17, 18);
default: return LC_MakeBP(0, 0);
case LC_TokenKind_Mul: case LC_TokenKind_Div: case LC_TokenKind_Mod: return LC_MakePrecedence(17, 18);
default: return LC_MakePrecedence(0, 0);
}
Postfix:
switch (kind) {
case LC_TokenKind_Dot: case LC_TokenKind_OpenBracket: case LC_TokenKind_OpenParen: return LC_MakeBP(21, -2);
default: return LC_MakeBP(-1, -1);
case LC_TokenKind_Dot: case LC_TokenKind_OpenBracket: case LC_TokenKind_OpenParen: return LC_MakePrecedence(21, -2);
default: return LC_MakePrecedence(-1, -1);
}
}
@@ -142,7 +138,7 @@ LC_FUNCTION LC_AST *LC_ParseExprEx(int min_bp) {
LC_AST *left = NULL;
LC_Token *prev = LC_GetI(-1);
LC_Token *t = LC_Next();
LC_BindingPower prefixbp = LC_GetBindingPower(LC_Binding_Prefix, t->kind);
LC_Precedence prefixbp = LC_GetPrecedence(LC_PrecedenceKind_Prefix, t->kind);
// parse prefix expression
switch (t->kind) {
@@ -240,8 +236,8 @@ LC_FUNCTION LC_AST *LC_ParseExprEx(int min_bp) {
// it's not so we don't recurse - we break
// We do the for loop instead
LC_BindingPower postfix_bp = LC_GetBindingPower(LC_Binding_Postfix, t->kind);
LC_BindingPower infix_bp = LC_GetBindingPower(LC_Binding_Infix, t->kind);
LC_Precedence postfix_bp = LC_GetPrecedence(LC_PrecedenceKind_Postfix, t->kind);
LC_Precedence infix_bp = LC_GetPrecedence(LC_PrecedenceKind_Infix, t->kind);
// parse postfix expression
if (postfix_bp.left > min_bp) {