diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..378674a --- /dev/null +++ b/.clang-format @@ -0,0 +1,220 @@ +--- +AccessModifierOffset: 0 +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: Always +IndentAccessModifiers: true +TabWidth: 4 +UseTab: Never +UseCRLF: false +Language: Cpp +IndentWidth: 4 +AlignAfterOpenBracket: DontAlign +AlignArrayOfStructures: Left +AlignConsecutiveAssignments: AcrossComments +AlignConsecutiveBitFields: AcrossComments +AlignConsecutiveDeclarations: None +AlignConsecutiveMacros: AcrossComments +AlignEscapedNewlines: Left +AlignOperands: AlignAfterOperator +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: None +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: No +BinPackArguments: false +BinPackParameters: false +AttributeMacros: + - __capability +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: true + BeforeWhile: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBraces: Custom +BreakAfterJavaFieldAnnotations: false +BreakBeforeBinaryOperators: All +BreakBeforeConceptDeclarations: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +BreakInheritanceList: AfterColon +BreakStringLiterals: false +ColumnLimit: 80 +CommentPragmas: "^ IWYU pragma:" +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: true +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Regroup +IncludeCategories: + - Regex: ^ + Priority: 2 + CaseSensitive: false + SortPriority: 0 + - Regex: ^<.*\.h> + Priority: 1 + CaseSensitive: false + SortPriority: 0 + - Regex: ^<.* + Priority: 2 + CaseSensitive: false + SortPriority: 0 + - Regex: .* + Priority: 0 + CaseSensitive: false + SortPriority: 0 +IncludeIsMainRegex: ([-_](test|unittest))?$ +IncludeIsMainSourceRegex: "" +IndentCaseBlocks: true +IndentCaseLabels: true +IndentExternBlock: Indent +IndentGotoLabels: false +IndentPPDirectives: BeforeHash +IndentRequires: true +IndentWrappedFunctionNames: true +InsertTrailingCommas: None +JavaScriptQuotes: Double +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: OuterScope +MacroBlockBegin: "" +MacroBlockEnd: "" +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 4 +ObjCBreakBeforeNestedBlockParam: false +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true +PPIndentWidth: 4 +PackConstructorInitializers: Never +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +QualifierAlignment: Left +RawStringFormats: + - Language: Cpp + BasedOnStyle: google + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - c++ + - C++ + CanonicalDelimiter: "" + - Language: TextProto + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + - ParseTestProto + - ParsePartialTestProto + BasedOnStyle: google + Delimiters: + - pb + - PB + - proto + - PROTO + CanonicalDelimiter: pb +ReferenceAlignment: Left +ReflowComments: false +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Always +ShortNamespaceLines: 0 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: true +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: Custom +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: false + AfterFunctionDeclarationName: false + AfterFunctionDefinitionName: false + AfterIfMacros: false + AfterOverloadedOperator: true + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInCStyleCastParentheses: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: 1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..4a1c397 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,33 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-case-conflict + - id: mixed-line-ending + - id: check-added-large-files + - id: check-executables-have-shebangs + - id: check-shebang-scripts-are-executable + - id: detect-private-key + - id: no-commit-to-branch + args: [--branch, master, --branch, develop] + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: v14.0.6 + hooks: + - id: clang-format + types_or: [c++, c] + args: ["-style=file"] + - repo: https://github.com/Lucas-C/pre-commit-hooks + rev: v1.3.1 + hooks: + - id: forbid-crlf + - id: forbid-tabs +#- repo: https://github.com/pocc/pre-commit-hooks +# rev: v1.3.5 +# hooks: +# - id: clang-tidy +# args: [-checks=clang-diagnostic-return-type] +# files: src/.*\.cpp diff --git a/compile_commands.json b/compile_commands.json new file mode 100644 index 0000000..70b729b --- /dev/null +++ b/compile_commands.json @@ -0,0 +1,20 @@ +[ + { + "directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir", + "command": "clang++ -Isrc/obelisk.p -Isrc -I../src -fcolor-diagnostics -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -O0 -g -MD -MQ src/obelisk.p/obelisk.cpp.o -MF src/obelisk.p/obelisk.cpp.o.d -o src/obelisk.p/obelisk.cpp.o -c ../src/obelisk.cpp", + "file": "../src/obelisk.cpp", + "output": "src/obelisk.p/obelisk.cpp.o" + }, + { + "directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir", + "command": "clang++ -Isrc/obelisk.p -Isrc -I../src -fcolor-diagnostics -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -O0 -g -MD -MQ src/obelisk.p/lexer.cpp.o -MF src/obelisk.p/lexer.cpp.o.d -o src/obelisk.p/lexer.cpp.o -c ../src/lexer.cpp", + "file": "../src/lexer.cpp", + "output": "src/obelisk.p/lexer.cpp.o" + }, + { + "directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir", + "command": "clang++ -Isrc/obelisk.p -Isrc -I../src -fcolor-diagnostics -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -O0 -g -MD -MQ src/obelisk.p/parser.cpp.o -MF src/obelisk.p/parser.cpp.o.d -o src/obelisk.p/parser.cpp.o -c ../src/parser.cpp", + "file": "../src/parser.cpp", + "output": "src/obelisk.p/parser.cpp.o" + } +] diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..7b2deae --- /dev/null +++ b/meson.build @@ -0,0 +1,11 @@ +project('obelisk', + 'cpp', + version : '1.0.0', + default_options : [ + 'warning_level=3', + 'c_std=c17', + 'cpp_std=c++17' + ] +) + +subdir('src') diff --git a/src/ast/call_expression_ast.h b/src/ast/call_expression_ast.h new file mode 100644 index 0000000..247e0fb --- /dev/null +++ b/src/ast/call_expression_ast.h @@ -0,0 +1,34 @@ +#ifndef OBELISK_AST_CALL_EXPRESSION_AST_H +#define OBELISK_AST_CALL_EXPRESSION_AST_H + +#include "ast/expression_ast.h" + +#include +#include +#include + +namespace obelisk +{ + class CallExpressionAST : public ExpressionAST + { + private: + std::string callee_; + std::vector> args_; + + std::string getCallee(); + void setCallee(std::string callee); + + std::vector> getArgs(); + void setArgs(std::vector> args); + + public: + CallExpressionAST(const std::string &callee, + std::vector> args) : + callee_(callee), + args_(std::move(args)) + { + } + }; +} // namespace obelisk + +#endif diff --git a/src/ast/expression_ast.h b/src/ast/expression_ast.h new file mode 100644 index 0000000..11ba2d9 --- /dev/null +++ b/src/ast/expression_ast.h @@ -0,0 +1,13 @@ +#ifndef OBELISK_AST_EXPRESSION_AST_H +#define OBELISK_AST_EXPRESSION_AST_H + +namespace obelisk +{ + class ExpressionAST + { + public: + virtual ~ExpressionAST() = default; + }; +} // namespace obelisk + +#endif diff --git a/src/ast/function_ast.h b/src/ast/function_ast.h new file mode 100644 index 0000000..1d4ff4a --- /dev/null +++ b/src/ast/function_ast.h @@ -0,0 +1,30 @@ +#ifndef OBELISK_AST_FUNCTION_AST_H +#define OBELISK_AST_FUNCTION_AST_H + +#include "ast/expression_ast.h" +#include "ast/prototype_ast.h" + +#include + +namespace obelisk +{ + class FunctionAST + { + private: + std::unique_ptr prototype_; + std::unique_ptr body_; + + std::unique_ptr getPrototype(); + void setPrototype(std::unique_ptr prototype); + + public: + FunctionAST(std::unique_ptr prototype, + std::unique_ptr body) : + prototype_(std::move(prototype)), + body_(std::move(body)) + { + } + }; +} // namespace obelisk + +#endif diff --git a/src/ast/meson.build b/src/ast/meson.build new file mode 100644 index 0000000..afb5a71 --- /dev/null +++ b/src/ast/meson.build @@ -0,0 +1,8 @@ +obelisk_ast_sources = files( + 'call_expression_ast.h', + 'expression_ast.h', + 'function_ast.h', + 'number_expression_ast.h', + 'prototype_ast.h', + 'variable_expression_ast.h' +) diff --git a/src/ast/number_expression_ast.h b/src/ast/number_expression_ast.h new file mode 100644 index 0000000..568e2d6 --- /dev/null +++ b/src/ast/number_expression_ast.h @@ -0,0 +1,24 @@ +#ifndef OBELISK_AST_NUMBER_EXPRESSION_AST_H +#define OBELISK_AST_NUMBER_EXPRESSION_AST_H + +#include "ast/expression_ast.h" + +namespace obelisk +{ + class NumberExpressionAST : public ExpressionAST + { + private: + double number_; + + double getNumber(); + void setNumber(double number); + + public: + NumberExpressionAST(double number) : + number_(number) + { + } + }; +} // namespace obelisk + +#endif diff --git a/src/ast/prototype_ast.h b/src/ast/prototype_ast.h new file mode 100644 index 0000000..c461fb8 --- /dev/null +++ b/src/ast/prototype_ast.h @@ -0,0 +1,34 @@ +#ifndef OBELISK_AST_PROTOTYPE_AST_H +#define OBELISK_AST_PROTOTYPE_AST_H + +#include +#include + +namespace obelisk +{ + class PrototypeAST + { + private: + std::string name_; + std::vector args_; + + void setName(const std::string& name); + std::vector getArgs(); + void setArgs(std::vector args); + + public: + PrototypeAST(const std::string& name, + std::vector args) : + name_(name), + args_(std::move(args)) + { + } + + const std::string& getName() const + { + return name_; + } + }; +} //namespace obelisk + +#endif diff --git a/src/ast/variable_expression_ast.h b/src/ast/variable_expression_ast.h new file mode 100644 index 0000000..6089080 --- /dev/null +++ b/src/ast/variable_expression_ast.h @@ -0,0 +1,25 @@ +#ifndef OBELISK_AST_VARIABLE_EXPRESSION_AST_H +#define OBELISK_AST_VARIABLE_EXPRESSION_AST_H + +#include "ast/expression_ast.h" + +#include + +namespace obelisk +{ + class VariableExpressionAST : public ExpressionAST + { + private: + std::string name_; + std::string getName(); + void setName(const std::string name); + + public: + VariableExpressionAST(const std::string &name) : + name_(name) + { + } + }; +} //namespace obelisk + +#endif diff --git a/src/lexer.cpp b/src/lexer.cpp new file mode 100644 index 0000000..6955b60 --- /dev/null +++ b/src/lexer.cpp @@ -0,0 +1,121 @@ +#include "lexer.h" + +#include + +int obelisk::Lexer::getToken() +{ + static int lastChar = ' '; + + while (isspace(lastChar)) + { + lastChar = getchar(); + } + + if (isalpha(lastChar)) + { + eraseIdentifier(); + appendIdentifier(lastChar); + while (isalnum((lastChar = getchar()))) + { + appendIdentifier(lastChar); + } + + if (getIdentifier() == "def") + { + return Token::kTokenDef; + } + + if (getIdentifier() == "extern") + { + return kTokenExtern; + } + + return kTokenIdentifier; + } + + if (isdigit(lastChar) || lastChar == '.') + { + std::string numberStr; + do + { + numberStr += lastChar; + lastChar = getchar(); + } + while (isdigit(lastChar) || lastChar == '.'); + + setNumberValue(strtod(numberStr.c_str(), nullptr)); + + return kTokenNumber; + } + + if (lastChar == '#') + { + commentLine(&lastChar); + + if (lastChar != EOF) + { + return getToken(); + } + } + else if (lastChar == '/') + { + lastChar = getchar(); + if (lastChar == '/') + { + commentLine(&lastChar); + + if (lastChar != EOF) + { + return getToken(); + } + } + } + + if (lastChar == EOF) + { + return kTokenEof; + } + + int thisChar = lastChar; + lastChar = getchar(); + return thisChar; +} + +void obelisk::Lexer::commentLine(int* lastChar) +{ + do + { + *lastChar = getchar(); + } + while (*lastChar != EOF && *lastChar != '\n' && *lastChar != '\r'); +} + +std::string obelisk::Lexer::getIdentifier() +{ + return identifier_; +} + +void obelisk::Lexer::setIdentifier(const std::string identifier) +{ + identifier_ = identifier; +} + +void obelisk::Lexer::eraseIdentifier() +{ + identifier_ = ""; +} + +void obelisk::Lexer::appendIdentifier(int lastChar) +{ + identifier_ += lastChar; +} + +double obelisk::Lexer::getNumberValue() +{ + return numberValue_; +} + +void obelisk::Lexer::setNumberValue(double numberValue) +{ + numberValue_ = numberValue; +} diff --git a/src/lexer.h b/src/lexer.h new file mode 100644 index 0000000..20a0c96 --- /dev/null +++ b/src/lexer.h @@ -0,0 +1,46 @@ +#ifndef OBELISK_LEXER_H +#define OBELISK_LEXER_H + +#include + +namespace obelisk +{ + + class Lexer + { + private: + std::string identifier_; + double numberValue_; + + void setIdentifier(const std::string identifier); + void eraseIdentifier(); + void appendIdentifier(int lastChar); + void setNumberValue(double numberValue); + void commentLine(int* lastChar); + + public: + enum Token + { + kTokenInvalid = -1, + kTokenEof = -2, + + // commands + kTokenFact = -3, + kTokenRule = -4, + kTokenDef = -5, + kTokenExtern = -6, + + // primary + kTokenIdentifier = -7, + kTokenNumber = -8, + kTokenString = -9 + }; + + int getToken(); + + std::string getIdentifier(); + double getNumberValue(); + }; +} // namespace obelisk + +#endif diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..3be46cd --- /dev/null +++ b/src/meson.build @@ -0,0 +1,13 @@ +obelisk_sources = files( + 'obelisk.cpp', + 'lexer.cpp', + 'parser.cpp' +) + +subdir('ast') +obelisk_sources += obelisk_ast_sources + +executable('obelisk', + obelisk_sources, + install : true +) diff --git a/src/obelisk.cpp b/src/obelisk.cpp new file mode 100644 index 0000000..90bf451 --- /dev/null +++ b/src/obelisk.cpp @@ -0,0 +1,50 @@ +#include "lexer.h" +#include "obelisk.h" +#include "parser.h" + +#include + +static void mainLoop() +{ + obelisk::Parser* parser = new obelisk::Parser(); + + // Prime the first token. + fprintf(stderr, "ready> "); + parser->getNextToken(); + + while (true) + { + fprintf(stderr, "ready> "); + switch (parser->getCurrentToken()) + { + case obelisk::Lexer::kTokenEof : + return; + case obelisk::Lexer::kTokenInvalid : + std::cerr << "Invalid token!\n"; + parser->getNextToken(); + return; + case ';' : // ignore top-level semicolons. + std::cout << "Identifier: " + << parser->getLexer()->getIdentifier() << std::endl; + std::cout << "Num: " << parser->getLexer()->getNumberValue() + << std::endl; + parser->getNextToken(); + break; + default : + parser->getNextToken(); + break; + } + } +} + +int main(int argc, char** argv) +{ + for (int i = 1; i < argc; i++) + { + std::cout << argv[i] << std::endl; + } + + mainLoop(); + + return EXIT_SUCCESS; +} diff --git a/src/obelisk.h b/src/obelisk.h new file mode 100644 index 0000000..d964df7 --- /dev/null +++ b/src/obelisk.h @@ -0,0 +1 @@ +static void mainLoop(); diff --git a/src/parser.cpp b/src/parser.cpp new file mode 100644 index 0000000..9c783b5 --- /dev/null +++ b/src/parser.cpp @@ -0,0 +1,225 @@ +#include "ast/call_expression_ast.h" +#include "ast/number_expression_ast.h" +#include "ast/variable_expression_ast.h" +#include "parser.h" + +obelisk::Parser::Parser() +{ + lexer_ = new obelisk::Lexer(); +} + +obelisk::Parser::Parser(obelisk::Lexer* lexer) +{ + if (lexer != nullptr) + { + lexer_ = lexer; + } + else + { + Parser(); + } +} + +obelisk::Parser::~Parser() +{ + delete lexer_; +} + +obelisk::Lexer* obelisk::Parser::getLexer() +{ + return lexer_; +} + +int obelisk::Parser::getNextToken() +{ + setCurrentToken(getLexer()->getToken()); + return getCurrentToken(); +} + +int obelisk::Parser::getCurrentToken() +{ + return currentToken_; +} + +void obelisk::Parser::setCurrentToken(int currentToken) +{ + currentToken_ = currentToken; +} + +std::unique_ptr obelisk::Parser::logError( + const char* str) +{ + fprintf(stderr, "Error: %s\n", str); + return nullptr; +} + +std::unique_ptr obelisk::Parser::logErrorPrototype( + const char* str) +{ + logError(str); + return nullptr; +} + +std::unique_ptr obelisk::Parser::parseExpression() +{ + auto LHS = parsePrimary(); + if (!LHS) + { + return nullptr; + } + + return LHS; +} + +std::unique_ptr obelisk::Parser::parsePrimary() +{ + switch (getCurrentToken()) + { + case obelisk::Lexer::kTokenIdentifier : + return parseIdentifierExpression(); + case obelisk::Lexer::kTokenNumber : + return parseNumberExpression(); + case '(' : + return parseParenthesisExpression(); + default : + return logError("unknown token when expecting and expression"); + } +} + +std::unique_ptr obelisk::Parser::parseNumberExpression() +{ + auto result = std::make_unique( + getLexer()->getNumberValue()); + getNextToken(); + return std::move(result); +} + +std::unique_ptr + obelisk::Parser::parseParenthesisExpression() +{ + getNextToken(); + auto v = parseExpression(); + if (!v) + { + return nullptr; + } + + if (getCurrentToken() != ')') + { + return logError("expected ')'"); + } + getNextToken(); + return v; +} + +std::unique_ptr + obelisk::Parser::parseIdentifierExpression() +{ + std::string idName = getLexer()->getIdentifier(); + getNextToken(); + if (getCurrentToken() != '(') + { + return std::make_unique(idName); + } + + getNextToken(); + std::vector> args; + if (getCurrentToken() != ')') + { + while (true) + { + if (auto arg = parseExpression()) + { + args.push_back(std::move(arg)); + } + else + { + return nullptr; + } + + if (getCurrentToken() == ')') + { + break; + } + + if (getCurrentToken() != ',') + { + return logError("Expected ')' or ',' in argument list"); + } + + getNextToken(); + } + } + + getNextToken(); + return std::make_unique(idName, std::move(args)); +} + +std::unique_ptr obelisk::Parser::parsePrototype() +{ + if (getCurrentToken() != obelisk::Lexer::kTokenIdentifier) + { + return logErrorPrototype("Expected function name in prototype"); + } + + std::string functionName = getLexer()->getIdentifier(); + getNextToken(); + + if (getCurrentToken() != '(') + { + return logErrorPrototype("Expected '(' in prototype"); + } + + std::vector argNames; + while (getNextToken() == obelisk::Lexer::kTokenIdentifier) + { + argNames.push_back(getLexer()->getIdentifier()); + } + + if (getCurrentToken() != ')') + { + return logErrorPrototype("Expected ')' in prototype"); + } + + getNextToken(); + + return std::make_unique(functionName, + std::move(argNames)); +} + +std::unique_ptr obelisk::Parser::parseDefinition() +{ + getNextToken(); + auto prototype = parsePrototype(); + if (!prototype) + { + return nullptr; + } + + if (auto expression = parseExpression()) + { + return std::make_unique(std::move(prototype), + std::move(expression)); + } + + return nullptr; +} + +std::unique_ptr obelisk::Parser::parseTopLevelExpression() +{ + if (auto expression = parseExpression()) + { + // Make an anonymous prototype + auto prototype = std::make_unique("__anon_expr", + std::vector()); + return std::make_unique(std::move(prototype), + std::move(expression)); + } + return nullptr; +} + +std::unique_ptr obelisk::Parser::parseExtern() +{ + getNextToken(); + return parsePrototype(); +} diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 0000000..2a00bbc --- /dev/null +++ b/src/parser.h @@ -0,0 +1,53 @@ +#ifndef OBELISK_PARSER_H +#define OBELISK_PARSER_H + +#include "ast/expression_ast.h" +#include "ast/function_ast.h" +#include "ast/prototype_ast.h" +#include "lexer.h" + +#include + +namespace obelisk +{ + class Parser + { + private: + obelisk::Lexer* lexer_; + int currentToken_; + + void setCurrentToken(int currentToken); + + std::unique_ptr logError(const char* str); + std::unique_ptr logErrorPrototype( + const char* str); + + std::unique_ptr parseExpression(); + std::unique_ptr parseNumberExpression(); + std::unique_ptr + parseParenthesisExpression(); + std::unique_ptr parseIdentifierExpression(); + std::unique_ptr parsePrimary(); + std::unique_ptr parsePrototype(); + std::unique_ptr parseDefinition(); + std::unique_ptr parseTopLevelExpression(); + std::unique_ptr parseExtern(); + + public: + Parser(); + Parser(obelisk::Lexer* lexer); + ~Parser(); + + obelisk::Lexer* getLexer(); + + int getCurrentToken(); + + int getNextToken(); + + void handleDefinition(); + void handleExtern(); + void handleTopLevelExpression(); + }; +} // namespace obelisk + +#endif