Allowed multiple functions + non "main" functions

Also fixed a bug in the lexer and changed how AST is logged.
This commit is contained in:
Pasha Bibko
2025-05-08 16:03:54 +01:00
parent 794173e14f
commit 050eeb5a53
6 changed files with 56 additions and 14 deletions

View File

@@ -95,6 +95,9 @@ namespace LX
// The name of the function // // The name of the function //
std::string name; std::string name;
// The parameters of the function //
std::vector<std::string> params;
// The scope off the function // // The scope off the function //
Scope scope; Scope scope;

View File

@@ -8,9 +8,6 @@
namespace LX namespace LX
{ {
// Helper function for dealing with floating-point number literals //
static constexpr bool CanBePartOfNumberLiteral(const char c) { return (c == '.') || (c == 'f'); }
// Checks if the given word is a keyword before adding it to the tokens // // Checks if the given word is a keyword before adding it to the tokens //
static void TokenizeWord(const std::string& word, std::vector<Token>& tokens, LexerInfo& info) static void TokenizeWord(const std::string& word, std::vector<Token>& tokens, LexerInfo& info)
{ {
@@ -46,7 +43,7 @@ namespace LX
// Works out if the current character is alphabetic or numeric // // Works out if the current character is alphabetic or numeric //
info.isAlpha = (current >= 'a' && current <= 'z') || (current >= 'A' && current <= 'Z'); info.isAlpha = (current >= 'a' && current <= 'z') || (current >= 'A' && current <= 'Z');
info.isNumeric = (current >= '0' && current <= '9'); info.isNumeric = (current >= '0' && current <= '9') || (current == '.');
} }
// Only does next character checks when not at the end // // Only does next character checks when not at the end //
@@ -57,7 +54,7 @@ namespace LX
// Sets flags depending on the value of the next character // // Sets flags depending on the value of the next character //
info.isNextCharAlpha = (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'); info.isNextCharAlpha = (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z');
info.isNextCharNumeric = (next >= '0' && next <= '9') || CanBePartOfNumberLiteral(next); info.isNextCharNumeric = (next >= '0' && next <= '9') || (next == '.');
} }
// Else defaults the flags to false // // Else defaults the flags to false //
@@ -150,7 +147,7 @@ namespace LX
} }
// End of a number // // End of a number //
else if ((info.isNumeric == true || CanBePartOfNumberLiteral(current)) && info.isNextCharNumeric == false && info.lexingNumber == true) else if (info.isNumeric == true && info.isNextCharNumeric == false && info.lexingNumber == true)
{ {
// Pushes the number to the token vector. Number literals are stored as string in the tokens // // Pushes the number to the token vector. Number literals are stored as string in the tokens //
std::string num(info.source.data() + info.startOfNumberLiteral, (unsigned __int64)(info.index + 1) - info.startOfNumberLiteral); std::string num(info.source.data() + info.startOfNumberLiteral, (unsigned __int64)(info.index + 1) - info.startOfNumberLiteral);
@@ -160,7 +157,7 @@ namespace LX
// During a number // // During a number //
else if (info.isNumeric == true); else if (info.isNumeric == true);
else if (info.lexingNumber == true && CanBePartOfNumberLiteral(current)); else if (info.lexingNumber == true);
// Start of a word // // Start of a word //
else if (info.isAlpha == true && info.wasLastCharAlpha == false) else if (info.isAlpha == true && info.wasLastCharAlpha == false)

View File

@@ -37,6 +37,7 @@ namespace LX
TOKEN_CASE(Token::CLOSE_PAREN); TOKEN_CASE(Token::CLOSE_PAREN);
TOKEN_CASE(Token::ASSIGN); TOKEN_CASE(Token::ASSIGN);
TOKEN_CASE(Token::INT_DEC); TOKEN_CASE(Token::INT_DEC);
TOKEN_CASE(Token::COMMA);
// Default just returns it as it's numerical value // // Default just returns it as it's numerical value //
default: return "Unknown: " + std::to_string((int)type); default: return "Unknown: " + std::to_string((int)type);

View File

@@ -14,16 +14,35 @@ namespace LX
return true; return true;
} }
static llvm::GlobalValue::LinkageTypes GetLinkageType(const std::string& funcName)
{
if (funcName == "main")
{
return llvm::Function::ExternalLinkage;
}
else
{
return llvm::GlobalValue::InternalLinkage;
}
}
// Generates the LLVM IR for the given function // // Generates the LLVM IR for the given function //
static void GenerateFunctionIR(FunctionDefinition& funcAST, InfoLLVM& LLVM) static void GenerateFunctionIR(FunctionDefinition& funcAST, InfoLLVM& LLVM)
{ {
// Creates the functions signature and return type // // Creates the functions signature and return type //
llvm::FunctionType* retType = llvm::FunctionType::get(llvm::Type::getInt32Ty(LLVM.context), false); // <- Defaults to int currently llvm::FunctionType* retType = llvm::FunctionType::get(llvm::Type::getInt32Ty(LLVM.context), false); // <- Defaults to int currently
llvm::Function* func = llvm::Function::Create(retType, llvm::Function::ExternalLinkage, funcAST.name, LLVM.module); llvm::Function* func = llvm::Function::Create(retType, GetLinkageType(funcAST.name), funcAST.name, LLVM.module);
llvm::BasicBlock* entry = llvm::BasicBlock::Create(LLVM.context, "entry", func); llvm::BasicBlock* entry = llvm::BasicBlock::Create(LLVM.context, funcAST.name + "-entry", func);
LLVM.builder.SetInsertPoint(entry); LLVM.builder.SetInsertPoint(entry);
// Adds the function's parameters to the scope //
for (std::string& param : funcAST.params)
{
LLVM.scope->CreateVar(param, LLVM);
}
// Generates the IR within the function by looping over the nodes // // Generates the IR within the function by looping over the nodes //
for (auto& node : funcAST.body) for (auto& node : funcAST.body)
{ {

View File

@@ -185,9 +185,6 @@ namespace LX
// Turns the tokens of a file into it's abstract syntax tree equivalent // // Turns the tokens of a file into it's abstract syntax tree equivalent //
FileAST TurnTokensIntoAbstractSyntaxTree(std::vector<Token>& tokens, const std::filesystem::path& path) FileAST TurnTokensIntoAbstractSyntaxTree(std::vector<Token>& tokens, const std::filesystem::path& path)
{ {
// Logs the start of the parsing
Log::LogNewSection("Started parsing tokens");
// Creates the output storer and the parser // // Creates the output storer and the parser //
FileAST output; FileAST output;
ParserInfo p(tokens, path); ParserInfo p(tokens, path);
@@ -198,6 +195,7 @@ namespace LX
{ {
switch (p.tokens[p.index].type) switch (p.tokens[p.index].type)
{ {
// Wow this logic needs to be abstracted into a seperate function //
case Token::FUNCTION: case Token::FUNCTION:
{ {
// Skips over function token // // Skips over function token //
@@ -211,15 +209,34 @@ namespace LX
ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, p); ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, p);
func.name = p.tokens[p.index++].GetContents(); func.name = p.tokens[p.index++].GetContents();
// Logs the start of the AST section //
Log::LogNewSection("AST of: ", func.name);
// Checks for opening paren '(' // // Checks for opening paren '(' //
ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::OPEN_PAREN, Token::OPEN_PAREN, p); ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::OPEN_PAREN, Token::OPEN_PAREN, p);
p.index++; p.index++;
// Loops over all the arguments of the function // // Loops over all the parameters of the function //
// TODO: Do something with the parameters
while (p.index < p.len && (p.tokens[p.index].type == Token::CLOSE_PAREN) == false) while (p.index < p.len && (p.tokens[p.index].type == Token::CLOSE_PAREN) == false)
{ {
// Checks for type declaration //
ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::INT_DEC, Token::INT_DEC, p);
p.index++; p.index++;
// Checks for variable name //
ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, p);
std::string pName = p.tokens[p.index].contents;
p.index++;
// Checks for [comma/close paren] to close the variable declaration //
bool correctEnd = (p.tokens[p.index].type == Token::COMMA) || (p.tokens[p.index].type == Token::CLOSE_PAREN);
ThrowIf<UnexpectedToken>(correctEnd == false, Token::UNDEFINED, p.tokens[p.index], "end of parameters", p);
// Adds the variable to the current scope //
func.params.push_back(pName);
// Only iterates if not a close paren //
if (p.tokens[p.index].type != Token::CLOSE_PAREN) { p.index++; }
} }
// Skips over close bracket // // Skips over close bracket //

View File

@@ -1,3 +1,8 @@
func add(int a, int b)
{
return a + b
}
func main() func main()
{ {
int a int a