nitron

commit 76d2ba3c363e9194c1c158265dc41783cb0ccd7e

Author: mesyeti <mesyeti@mesyeti.uk>

add bitwise operators

 basic/source/frontend/c89.c | 41 +++++++----
 basic/source/lexer.c | 117 ++++++++++++++++++----------------
 basic/source/lexer.h | 12 ++-
 basic/source/parser.c | 38 +++++++++-
 basic/source/semanticAnalysis.c | 60 +++++++++++++++++
 basic/test.bas | 2 


diff --git a/basic/source/frontend/c89.c b/basic/source/frontend/c89.c
index 638c918ec87e07bd80566659e5cea48ca614527b..c6cb13fcaeaa9f8a82c709ab0d229db6d303e1fc 100644
--- a/basic/source/frontend/c89.c
+++ b/basic/source/frontend/c89.c
@@ -8,6 +8,7 @@ #include "../semanticAnalysis.h"
 
 static FILE* out;
 static bool  inMain;
+static bool  inFunc;
 
 static void Finish(bool program) {
 	if (program) {
@@ -78,15 +79,19 @@ static void CompileFuncDef(FuncDefNode* node) {
 	CompileDec(node->dec);
 	fprintf(out, " {\n");
 
+	inFunc = true;
+
 	for (size_t i = 0; i < node->bodyLen; ++ i) {
 		Compiler_CompileBodyNode(&node->body[i]);
 	}
 
 	fprintf(out, "}\n");
+
+	inFunc = false;
 }
 
 static void CompileDim(DimNode* node) {
-	if (inMain) return;
+	if (!inFunc) return;
 
 	UsedType usedType = SemanticAnalysis_NodeAsUsedType(node->varType);
 	Type*    type     = &state.types[usedType.typeIdx];
@@ -143,16 +148,19 @@ 			fprintf(out, "(");
 			CompileExprNode(node->bin.left);
 
 			switch (node->bin.op) {
-				case TOKEN_ADD:       fprintf(out, "+");  break;
-				case TOKEN_SUBTRACT:  fprintf(out, "-");  break;
-				case TOKEN_MULTIPLY:  fprintf(out, "*");  break;
-				case TOKEN_DIVIDE:    fprintf(out, "/");  break;
-				case TOKEN_MOD:       fprintf(out, "%%"); break;
-				case TOKEN_EQUAL:     fprintf(out, "=="); break;
-				case TOKEN_LESS:      fprintf(out, "<");  break;
-				case TOKEN_GREATER:   fprintf(out, ">");  break;
-				case TOKEN_ASSIGN:    fprintf(out, "=");  break;
-				case TOKEN_NOT_EQUAL: fprintf(out, "!="); break;
+				case TOKEN_ADD:         fprintf(out, "+");  break;
+				case TOKEN_SUBTRACT:    fprintf(out, "-");  break;
+				case TOKEN_MULTIPLY:    fprintf(out, "*");  break;
+				case TOKEN_DIVIDE:      fprintf(out, "/");  break;
+				case TOKEN_MOD:         fprintf(out, "%%"); break;
+				case TOKEN_EQUAL:       fprintf(out, "=="); break;
+				case TOKEN_LESS:        fprintf(out, "<");  break;
+				case TOKEN_GREATER:     fprintf(out, ">");  break;
+				case TOKEN_ASSIGN:      fprintf(out, "=");  break;
+				case TOKEN_NOT_EQUAL:   fprintf(out, "!="); break;
+				case TOKEN_ACCESS_XOR:  fprintf(out, "^");  break;
+				case TOKEN_ADDRESS_AND: fprintf(out, "&");  break;
+				case TOKEN_BIT_OR:      fprintf(out, "|");  break;
 				case TOKEN_DOT: {
 					UsedType type = SemanticAnalysis_NodeAsUsedType(node->bin.left);
 
@@ -182,11 +190,12 @@ 		case NODE_UNARY_OP: {
 			fprintf(out, "(");
 
 			switch (node->unary.op) {
-				case TOKEN_ADD:      fprintf(out, "+"); break;
-				case TOKEN_SUBTRACT: fprintf(out, "-"); break;
-				case TOKEN_ADDRESS:  fprintf(out, "&"); break;
-				case TOKEN_ACCESS:   fprintf(out, "*"); break;
-				case TOKEN_NOT:      fprintf(out, "!"); break;
+				case TOKEN_ADD:          fprintf(out, "+"); break;
+				case TOKEN_SUBTRACT:     fprintf(out, "-"); break;
+				case TOKEN_ADDRESS_AND:  fprintf(out, "&"); break;
+				case TOKEN_ACCESS_XOR:   fprintf(out, "*"); break;
+				case TOKEN_NOT:          fprintf(out, "!"); break;
+				case TOKEN_BIT_NOT:      fprintf(out, "~"); break;
 				default: assert(0);
 			}
 




diff --git a/basic/source/lexer.c b/basic/source/lexer.c
index 1a385bd5a17d1a8f766f19be16866d59ebf55b6f..cf4355ddf929d399241d489a12283a9d928cd4c7 100644
--- a/basic/source/lexer.c
+++ b/basic/source/lexer.c
@@ -118,12 +118,8 @@ 			if (next == '=') {
 				*token = TOKEN(TOKEN_NOT_EQUAL, NULL);
 			}
 			else {
-				*token = TOKEN(TOKEN_NOT, NULL);
-
-				if (next == '\n') {
-					-- lexer->line;
-				}
-				fseek(lexer->file, -1, SEEK_CUR);
+				ErrorInfo err = {lexer->fileName, lexer->line};
+				PrintError(err, "Unexpected '%c'", next);
 			}
 			return LEXER_TOKEN;
 		}
@@ -144,13 +140,15 @@ 				fseek(lexer->file, -1, SEEK_CUR);
 			}
 			return LEXER_TOKEN;
 		}
-		case '<':  *token = TOKEN(TOKEN_LESS,    NULL); return LEXER_TOKEN;
-		case '>':  *token = TOKEN(TOKEN_GREATER, NULL); return LEXER_TOKEN;
-		case '&':  *token = TOKEN(TOKEN_ADDRESS, NULL); return LEXER_TOKEN;
-		case '^':  *token = TOKEN(TOKEN_ACCESS,  NULL); return LEXER_TOKEN;
-		case '\n': *token = TOKEN(TOKEN_LINE,    NULL); return LEXER_TOKEN;
-		case '[':  *token = TOKEN(TOKEN_LSQUARE, NULL); return LEXER_TOKEN;
-		case ']':  *token = TOKEN(TOKEN_RSQUARE, NULL); return LEXER_TOKEN;
+		case '<':  *token = TOKEN(TOKEN_LESS,        NULL); return LEXER_TOKEN;
+		case '>':  *token = TOKEN(TOKEN_GREATER,     NULL); return LEXER_TOKEN;
+		case '&':  *token = TOKEN(TOKEN_ADDRESS_AND, NULL); return LEXER_TOKEN;
+		case '^':  *token = TOKEN(TOKEN_ACCESS_XOR,  NULL); return LEXER_TOKEN;
+		case '\n': *token = TOKEN(TOKEN_LINE,        NULL); return LEXER_TOKEN;
+		case '[':  *token = TOKEN(TOKEN_LSQUARE,     NULL); return LEXER_TOKEN;
+		case ']':  *token = TOKEN(TOKEN_RSQUARE,     NULL); return LEXER_TOKEN;
+		case '|':  *token = TOKEN(TOKEN_BIT_OR,      NULL); return LEXER_TOKEN;
+		case '~':  *token = TOKEN(TOKEN_BIT_NOT,     NULL); return LEXER_TOKEN;
 		case '\'': { // comment
 			while (true) {
 				GET_CHAR(ch);
@@ -202,7 +200,10 @@ 				{"type",     TOKEN_TYPE},
 				{"union",    TOKEN_UNION},
 				{"program",  TOKEN_PROGRAM},
 				{"import",   TOKEN_IMPORT},
-				{"return",   TOKEN_RETURN}
+				{"return",   TOKEN_RETURN},
+				{"not",      TOKEN_NOT},
+				{"and",      TOKEN_AND},
+				{"or",       TOKEN_OR}
 			};
 
 			for (size_t i = 0; i < sizeof(keywords) / sizeof(Keyword); ++ i) {
@@ -221,48 +222,52 @@ }
 
 const char* Lexer_TypeVAsString(TokenType type) {
 	switch (type) {
-		case TOKEN_NULL:       return "null";
-		case TOKEN_EXTERN:     return "extern";
-		case TOKEN_FUNC:       return "func";
-		case TOKEN_SUB:        return "sub";
-		case TOKEN_DIM:        return "dim";
-		case TOKEN_AS:         return "as";
-		case TOKEN_QUIT:       return "quit";
-		case TOKEN_PTR:        return "ptr";
-		case TOKEN_END:        return "end";
-		case TOKEN_IF:         return "if";
-		case TOKEN_THEN:       return "then";
-		case TOKEN_ELSE:       return "else";
-		case TOKEN_WHILE:      return "while";
-		case TOKEN_DO:         return "do";
-		case TOKEN_TYPE:       return "type";
-		case TOKEN_UNION:      return "union";
-		case TOKEN_PROGRAM:    return "program";
-		case TOKEN_IMPORT:     return "import";
-		case TOKEN_RETURN:     return "return";
-		case TOKEN_IDENTIFIER: return "identifier";
-		case TOKEN_STRING:     return "string";
-		case TOKEN_INT:        return "int";
-		case TOKEN_LINE:       return "line";
-		case TOKEN_LPAREN:     return "lparen";
-		case TOKEN_RPAREN:     return "rparen";
-		case TOKEN_DOT:        return "dot";
-		case TOKEN_COMMA:      return "comma";
-		case TOKEN_LSQUARE:    return "left square";
-		case TOKEN_RSQUARE:    return "right square";
-		case TOKEN_ADD:        return "add";
-		case TOKEN_SUBTRACT:   return "subtract";
-		case TOKEN_MULTIPLY:   return "multiply";
-		case TOKEN_DIVIDE:     return "divide";
-		case TOKEN_MOD:        return "mod";
-		case TOKEN_EQUAL:      return "equal";
-		case TOKEN_LESS:       return "less";
-		case TOKEN_GREATER:    return "greater";
-		case TOKEN_ADDRESS:    return "address";
-		case TOKEN_ACCESS:     return "access";
-		case TOKEN_NOT:        return "not";
-		case TOKEN_NOT_EQUAL:  return "not equal";
-		default:               assert(0);
+		case TOKEN_NULL:        return "null";
+		case TOKEN_EXTERN:      return "extern";
+		case TOKEN_FUNC:        return "func";
+		case TOKEN_SUB:         return "sub";
+		case TOKEN_DIM:         return "dim";
+		case TOKEN_AS:          return "as";
+		case TOKEN_QUIT:        return "quit";
+		case TOKEN_PTR:         return "ptr";
+		case TOKEN_END:         return "end";
+		case TOKEN_IF:          return "if";
+		case TOKEN_THEN:        return "then";
+		case TOKEN_ELSE:        return "else";
+		case TOKEN_WHILE:       return "while";
+		case TOKEN_DO:          return "do";
+		case TOKEN_TYPE:        return "type";
+		case TOKEN_UNION:       return "union";
+		case TOKEN_PROGRAM:     return "program";
+		case TOKEN_IMPORT:      return "import";
+		case TOKEN_RETURN:      return "return";
+		case TOKEN_NOT:         return "not";
+		case TOKEN_AND:         return "and";
+		case TOKEN_OR:          return "or";
+		case TOKEN_IDENTIFIER:  return "identifier";
+		case TOKEN_STRING:      return "string";
+		case TOKEN_INT:         return "int";
+		case TOKEN_LINE:        return "line";
+		case TOKEN_LPAREN:      return "lparen";
+		case TOKEN_RPAREN:      return "rparen";
+		case TOKEN_DOT:         return "dot";
+		case TOKEN_COMMA:       return "comma";
+		case TOKEN_LSQUARE:     return "left square";
+		case TOKEN_RSQUARE:     return "right square";
+		case TOKEN_ADD:         return "add";
+		case TOKEN_SUBTRACT:    return "subtract";
+		case TOKEN_MULTIPLY:    return "multiply";
+		case TOKEN_DIVIDE:      return "divide";
+		case TOKEN_MOD:         return "mod";
+		case TOKEN_EQUAL:       return "equal";
+		case TOKEN_LESS:        return "less";
+		case TOKEN_GREATER:     return "greater";
+		case TOKEN_ACCESS_XOR:  return "access/bitwise xor";
+		case TOKEN_ADDRESS_AND: return "address/bitwise and";
+		case TOKEN_NOT_EQUAL:   return "not equal";
+		case TOKEN_BIT_OR:      return "bitwise or";
+		case TOKEN_BIT_NOT:     return "bitwise not";
+		default:                assert(0);
 	}
 }
 




diff --git a/basic/source/lexer.h b/basic/source/lexer.h
index 3e69d894e04c7addcd8704162ca225d804184f27..13c65731d6b8dec21001e81d54eac723105584a1 100644
--- a/basic/source/lexer.h
+++ b/basic/source/lexer.h
@@ -27,6 +27,9 @@ 	TOKEN_UNION,
 	TOKEN_PROGRAM,
 	TOKEN_IMPORT,
 	TOKEN_RETURN,
+	TOKEN_NOT,
+	TOKEN_AND,
+	TOKEN_OR,
 
 	// misc
 	TOKEN_IDENTIFIER,
@@ -52,10 +55,11 @@ 	TOKEN_EQUAL,
 	TOKEN_LESS,
 	TOKEN_GREATER,
 	TOKEN_ASSIGN,
-	TOKEN_ADDRESS,
-	TOKEN_ACCESS,
-	TOKEN_NOT,
-	TOKEN_NOT_EQUAL
+	TOKEN_ACCESS_XOR,
+	TOKEN_ADDRESS_AND,
+	TOKEN_NOT_EQUAL,
+	TOKEN_BIT_OR,
+	TOKEN_BIT_NOT
 } TokenType;
 
 enum {




diff --git a/basic/source/parser.c b/basic/source/parser.c
index 9b52e190c69d437e8ba0e61b72ee3ac00f667554..cb7ce0fb159f75ed5430e4cee67cdfbd1c15a76f 100644
--- a/basic/source/parser.c
+++ b/basic/source/parser.c
@@ -122,9 +122,10 @@ static bool IsUnaryOperator(Token* tok) {
 	switch (tok->type) {
 		case TOKEN_ADD:
 		case TOKEN_SUBTRACT:
-		case TOKEN_ADDRESS:
-		case TOKEN_ACCESS:
-		case TOKEN_NOT:      return true;
+		case TOKEN_ADDRESS_AND:
+		case TOKEN_ACCESS_XOR:
+		case TOKEN_NOT:
+		case TOKEN_BIT_NOT:  return true;
 		default:             return false;
 	}
 }
@@ -246,8 +247,33 @@
 	return left;
 }
 
+static Node ParseBitwise(Parser* p) {
+	Node left = ParseAddSub(p);
+
+	while (
+		(p->tokens[p->i].type == TOKEN_ACCESS_XOR) ||
+		(p->tokens[p->i].type == TOKEN_ADDRESS_AND) ||
+		(p->tokens[p->i].type == TOKEN_BIT_OR)
+	) {
+		TokenType op = p->tokens[p->i].type;
+		Advance(p);
+		Node right = ParseAddSub(p);
+
+		Node* leftPtr  = SafeMalloc(sizeof(Node));
+		Node* rightPtr = SafeMalloc(sizeof(Node));
+		*leftPtr       = left;
+		*rightPtr      = right;
+
+		left.bin = (BinaryNode) {
+			INFO(NODE_BINARY_OP), leftPtr, rightPtr, op
+		};
+	}
+
+	return left;
+}
+
 static Node ParseComparison(Parser* p) {
-	Node left = ParseAddSub(p);
+	Node left = ParseBitwise(p);
 
 	while (
 		(p->tokens[p->i].type == TOKEN_EQUAL) ||
@@ -257,7 +283,7 @@ 		(p->tokens[p->i].type == TOKEN_NOT_EQUAL)
 	) {
 		TokenType op = p->tokens[p->i].type;
 		Advance(p);
-		Node right = ParseAddSub(p);
+		Node right = ParseBitwise(p);
 
 		Node* leftPtr  = SafeMalloc(sizeof(Node));
 		Node* rightPtr = SafeMalloc(sizeof(Node));
@@ -745,7 +771,7 @@ 		case TOKEN_PROGRAM: return ParseProgram(p);
 		case TOKEN_IMPORT:  return ParseImport(p);
 		case TOKEN_RETURN:  return ParseReturn(p);
 		case TOKEN_LPAREN:
-		case TOKEN_ACCESS:
+		case TOKEN_ACCESS_XOR:
 		case TOKEN_IDENTIFIER: {
 			if (p->i == p->tokenNum - 1) {
 				PrintError(p->tokens[p->i].err, "Unexpected EOF");




diff --git a/basic/source/semanticAnalysis.c b/basic/source/semanticAnalysis.c
index 610d709c48dffe66a8316c13f56401ba5685a47a..9eb9f24829a08d064b4b1e59d41ca94eb3143539 100644
--- a/basic/source/semanticAnalysis.c
+++ b/basic/source/semanticAnalysis.c
@@ -275,6 +275,18 @@ 						PrintError(node->i.err, "Cannot add float to pointer");
 					}
 					return left;
 				}
+				case TOKEN_ACCESS_XOR:
+				case TOKEN_ADDRESS_AND:
+				case TOKEN_BIT_OR: {
+					if (leftType->type != TYPE_PRIM) {
+						PrintError(node->i.err, "Using non-primitive type in bitwise operation");
+					}
+
+					if ((rightType->primType != PRIM_UINT) && (rightType->primType != PRIM_INT)) {
+						PrintError(node->i.err, "Can only use integers for bitwise operations");
+					}
+					return right;
+				}
 				default: {
 					PrintError(
 						node->i.err, "Operation '%s' not allowed here",
@@ -293,6 +305,18 @@ 					PrintError(node->i.err, "Cannot add float to pointer");
 				}
 				return right;
 			}
+			case TOKEN_ACCESS_XOR:
+			case TOKEN_ADDRESS_AND:
+			case TOKEN_BIT_OR: {
+				if (leftType->type != TYPE_PRIM) {
+					PrintError(node->i.err, "Using non-primitive type in bitwise operation");
+				}
+
+				if ((leftType->primType != PRIM_UINT) && (leftType->primType != PRIM_INT)) {
+					PrintError(node->i.err, "Can only use integers for bitwise operations");
+				}
+				return right;
+			}
 			default: {
 				PrintError(
 					node->i.err, "Operation '%s' not allowed here",
@@ -322,7 +346,7 @@ 			case TOKEN_DIVIDE:
 			case TOKEN_MOD: {
 				if ((leftType->type != TYPE_PRIM) || (rightType->type != TYPE_PRIM)) {
 					PrintError(
-						node->i.err, "Operation '%s' only works on primitives",
+						node->i.err, "Operation '%s' only works on primitive types",
 						Lexer_TypeVAsString(node->bin.op)
 					);
 				}
@@ -342,6 +366,23 @@ 						Lexer_TypeVAsString(node->bin.op)
 					);
 				}
 			}
+			case TOKEN_ACCESS_XOR:
+			case TOKEN_ADDRESS_AND:
+			case TOKEN_BIT_OR: {
+				if ((leftType->type != TYPE_PRIM) || (rightType->type != TYPE_PRIM)) {
+					PrintError(node->i.err, "Bitwise operations only work with primitive types");
+				}
+				if ((leftType->primType == PRIM_FLOAT) || (rightType->type == PRIM_FLOAT)) {
+					PrintError(node->i.err, "Bitwise operations do not work on floats");
+				}
+
+				if (leftType->size > rightType->size) {
+					return left;
+				}
+				else {
+					return right;
+				}
+			}
 			default: break;
 		}
 
@@ -413,16 +454,29 @@ 					}
 
 					return operand;
 				}
-				case TOKEN_ADDRESS: {
+				case TOKEN_ADDRESS_AND: {
 					++ operand.ptr;
 					return operand;
 				}
-				case TOKEN_ACCESS: {
+				case TOKEN_ACCESS_XOR: {
 					if (operand.ptr <= 0) {
 						PrintError(node->i.err, "Used access operator on non-pointer type");
 					}
 
 					-- operand.ptr;
+					return operand;
+				}
+				case TOKEN_BIT_NOT: {
+					if (type->type != TYPE_PRIM) {
+						PrintError(node->i.err,
+							"Only primitive types can be used with the +/- unary operators"
+						);
+					}
+
+					if ((type->primType != PRIM_UINT) && (type->primType != PRIM_INT)) {
+						PrintError(node->i.err, "Can only perform bitwise not operation on integer types");
+					}
+
 					return operand;
 				}
 				default: assert(0);




diff --git a/basic/test.bas b/basic/test.bas
index a42885304b30f991aedef977e1263ff2acb719e9..f97a4e6ee087a0b54c594adc79818f59c0105506 100644
--- a/basic/test.bas
+++ b/basic/test.bas
@@ -5,7 +5,7 @@
 extern func puts(str as ptr(char)) i32
 extern func printf(str as ptr(char), val as int) i32
 
-func add(a as int, b as int) i32
+func add(a as int, b as int) int
 	return a + b
 end