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 ## 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. - **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.
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. - 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.
I'm also considering the addition of overloaded procedures because it would greatly aid in writing macros.
# Language overview # 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 ## 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. 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 { typedef struct {
int left; int left;
int right; int right;
} LC_BindingPower; } LC_Precedence;
typedef enum { typedef enum {
LC_Binding_Prefix, LC_PrecedenceKind_Prefix,
LC_Binding_Infix, LC_PrecedenceKind_Infix,
LC_Binding_Postfix, LC_PrecedenceKind_Postfix,
} LC_Binding; } LC_PrecedenceKind;
typedef enum { typedef enum {
LC_CmpRes_LT, LC_CmpRes_LT,
@@ -828,12 +828,6 @@ struct LC_FileIter {
X(struct) \ X(struct) \
X(union) \ X(union) \
X(addptr) \ X(addptr) \
X(and) \
X(or) \
X(bit_and) \
X(bit_or) \
X(bit_xor) \
X(not ) \
X(true) \ X(true) \
X(false) 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_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_AST *LC_ParseTokens(LC_AST *package, LC_Lex *x);
LC_FUNCTION LC_Parser LC_MakeParser(LC_Lex *x); LC_FUNCTION LC_Parser LC_MakeParser(LC_Lex *x);
LC_FUNCTION LC_Parser *LC_MakeParserQuick(char *str); LC_FUNCTION LC_Parser *LC_MakeParserQuick(char *str);
LC_FUNCTION LC_Token *LC_Next(void); LC_FUNCTION LC_Token *LC_Next(void);
LC_FUNCTION LC_Token *LC_Get(void); LC_FUNCTION LC_Token *LC_Get(void);
LC_FUNCTION LC_Token *LC_GetI(int i); LC_FUNCTION LC_Token *LC_GetI(int i);
LC_FUNCTION LC_Token *LC_Is(LC_TokenKind kind); LC_FUNCTION LC_Token *LC_Is(LC_TokenKind kind);
LC_FUNCTION LC_Token *LC_IsKeyword(LC_Intern intern); LC_FUNCTION LC_Token *LC_IsKeyword(LC_Intern intern);
LC_FUNCTION LC_Token *LC_Match(LC_TokenKind kind); LC_FUNCTION LC_Token *LC_Match(LC_TokenKind kind);
LC_FUNCTION LC_Token *LC_MatchKeyword(LC_Intern intern); LC_FUNCTION LC_Token *LC_MatchKeyword(LC_Intern intern);
LC_FUNCTION LC_BindingPower LC_MakeBP(int left, int right); LC_FUNCTION LC_Precedence LC_GetPrecedence(LC_PrecedenceKind binding, LC_TokenKind kind);
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_ParseExprEx(int min_bp); LC_FUNCTION LC_AST *LC_ParseCompo(LC_Token *pos, LC_AST *left);
LC_FUNCTION LC_AST *LC_ParseCompo(LC_Token *pos, LC_AST *left); LC_FUNCTION LC_AST *LC_ParseExpr(void);
LC_FUNCTION LC_AST *LC_ParseExpr(void); LC_FUNCTION LC_AST *LC_ParseProcType(LC_Token *pos);
LC_FUNCTION LC_AST *LC_ParseProcType(LC_Token *pos); LC_FUNCTION LC_AST *LC_ParseType(void);
LC_FUNCTION LC_AST *LC_ParseType(void); LC_FUNCTION LC_AST *LC_ParseForStmt(LC_Token *pos);
LC_FUNCTION LC_AST *LC_ParseForStmt(LC_Token *pos); LC_FUNCTION LC_AST *LC_ParseSwitchStmt(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_ParseStmt(bool check_semicolon); LC_FUNCTION LC_AST *LC_ParseStmtBlock(int flags);
LC_FUNCTION LC_AST *LC_ParseStmtBlock(int flags); LC_FUNCTION LC_AST *LC_ParseProcDecl(LC_Token *name);
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_ParseStruct(LC_ASTKind kind, LC_Token *ident); LC_FUNCTION LC_AST *LC_ParseTypedef(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_CreateNote(LC_Token *pos, LC_Intern ident); LC_FUNCTION LC_AST *LC_ParseNote(void);
LC_FUNCTION LC_AST *LC_ParseNote(void); LC_FUNCTION LC_AST *LC_ParseNotes(void);
LC_FUNCTION LC_AST *LC_ParseNotes(void); LC_FUNCTION bool LC_ResolveBuildIf(LC_AST *build_if);
LC_FUNCTION bool LC_ResolveBuildIf(LC_AST *build_if); LC_FUNCTION LC_AST *LC_ParseImport(void);
LC_FUNCTION LC_AST *LC_ParseImport(void); LC_FUNCTION LC_AST *LC_ParseDecl(LC_AST *file);
LC_FUNCTION LC_AST *LC_ParseDecl(LC_AST *file); LC_FUNCTION bool LC_EatUntilNextValidDecl(void);
LC_FUNCTION bool LC_EatUntilNextValidDecl(void); LC_FUNCTION bool LC_ParseHashBuildOn(LC_AST *n);
LC_FUNCTION bool LC_ParseHashBuildOn(LC_AST *n); LC_FUNCTION LC_AST *LC_ParseFileEx(LC_AST *package);
LC_FUNCTION LC_AST *LC_ParseFileEx(LC_AST *package);
// //
// Resolution functions // Resolution functions

View File

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