initial commit
This commit is contained in:
13
CMakeLists.txt
Normal file
13
CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.31)
|
||||
project(TCompiler VERSION 0.0.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
|
||||
add_executable(TFC src/tfc.cpp
|
||||
src/lexer/Lexer.cpp
|
||||
src/lexer/Lexer.hpp
|
||||
src/parser/Parser.cpp
|
||||
src/parser/Parser.hpp
|
||||
)
|
||||
target_compile_options(TFC PRIVATE -Wall -Wextra)
|
||||
target_compile_definitions(TFC PRIVATE TEST)
|
||||
17
src/alib/colors.h
Normal file
17
src/alib/colors.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#define RESET "\033[0m" /* Reset */
|
||||
#define BLACK "\033[30m" /* Black */
|
||||
#define RED "\033[31m" /* Red */
|
||||
#define GREEN "\033[32m" /* Green */
|
||||
#define YELLOW "\033[33m" /* Yellow */
|
||||
#define BLUE "\033[34m" /* Blue */
|
||||
#define MAGENTA "\033[35m" /* Magenta */
|
||||
#define CYAN "\033[36m" /* Cyan */
|
||||
#define WHITE "\033[37m" /* White */
|
||||
#define BOLDBLACK "\033[1m\033[30m" /* Bold Black */
|
||||
#define BOLDRED "\033[1m\033[31m" /* Bold Red */
|
||||
#define BOLDGREEN "\033[1m\033[32m" /* Bold Green */
|
||||
#define BOLDYELLOW "\033[1m\033[33m" /* Bold Yellow */
|
||||
#define BOLDBLUE "\033[1m\033[34m" /* Bold Blue */
|
||||
#define BOLDMAGENTA "\033[1m\033[35m" /* Bold Magenta */
|
||||
#define BOLDCYAN "\033[1m\033[36m" /* Bold Cyan */
|
||||
#define BOLDWHITE "\033[1m\033[37m" /* Bold White */
|
||||
222
src/lexer/Lexer.cpp
Normal file
222
src/lexer/Lexer.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
//
|
||||
// Created by skythedragon on 6/24/25.
|
||||
//
|
||||
|
||||
#include "Lexer.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
inline std::string process_octal_escape(std::ifstream& file, char c)
|
||||
{
|
||||
std::string oct;
|
||||
oct += c;
|
||||
|
||||
while (true)
|
||||
{
|
||||
c = file.get();
|
||||
|
||||
if (!std::isdigit(c))
|
||||
{
|
||||
std::string ret;
|
||||
ret += static_cast<char>(std::stoi(oct, nullptr, 8));
|
||||
ret += c;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (std::stoi(oct + c, 0, 8) > 256)
|
||||
{
|
||||
std::string ret;
|
||||
ret += static_cast<char>(std::stoi(oct, nullptr, 8));
|
||||
ret += c;
|
||||
return ret;
|
||||
}
|
||||
|
||||
oct += c;
|
||||
}
|
||||
}
|
||||
|
||||
inline char process_hex_escape(std::ifstream& file)
|
||||
{
|
||||
std::string hex;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
char c = file.get();
|
||||
|
||||
if (!std::isxdigit(c))
|
||||
{
|
||||
if (hex.empty())
|
||||
{
|
||||
std::cout << "ERR: Unexpected character '" << c << "', expected hex digit.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return static_cast<char>(std::stoi(hex, nullptr, 16));
|
||||
}
|
||||
|
||||
hex += c;
|
||||
}
|
||||
|
||||
return static_cast<char>(std::stoi(hex, nullptr, 16));
|
||||
}
|
||||
|
||||
Lexer::Lexer(std::ifstream& file) : file_(std::move(file)) {}
|
||||
|
||||
void Lexer::lex()
|
||||
{
|
||||
while (file_.peek() != EOF)
|
||||
{
|
||||
char c = file_.get();
|
||||
|
||||
if (isalpha(c))
|
||||
{
|
||||
std::string lexeme;
|
||||
|
||||
lexeme += c;
|
||||
|
||||
while (!std::isspace(file_.peek()) && file_.peek() != EOF)
|
||||
{
|
||||
lexeme += file_.get();
|
||||
}
|
||||
|
||||
if (lexeme == "exit") {
|
||||
tokens_.emplace_back(TokenType::exit);
|
||||
} else {
|
||||
std::cerr << "ERR: Identifiers not supported " << lexeme << "\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (isdigit(c))
|
||||
{
|
||||
std::string lexeme;
|
||||
lexeme += c;
|
||||
|
||||
bool isnum = false;
|
||||
bool error = false;
|
||||
|
||||
while (std::isdigit(file_.peek()) || file_.peek() == '.')
|
||||
{
|
||||
lexeme += file_.get();
|
||||
|
||||
if (file_.peek() == '.')
|
||||
{
|
||||
isnum = true;
|
||||
}
|
||||
|
||||
if (isnum && file_.peek() == '.')
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
c = file_.get();
|
||||
|
||||
if (isalpha(c))
|
||||
{
|
||||
std::cerr << "ERR: Literal operators are not yet supported.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
std::cerr << "ERR: Ye dun bad\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (isnum) {
|
||||
tokens_.emplace_back(TokenType::number, lexeme);
|
||||
} else {
|
||||
tokens_.emplace_back(TokenType::integer, lexeme);
|
||||
}
|
||||
}
|
||||
|
||||
if (c == '"')
|
||||
{
|
||||
std::string lexeme;
|
||||
|
||||
while (true)
|
||||
{
|
||||
c = file_.get();
|
||||
|
||||
if (c == '"')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == EOF || c == '\n')
|
||||
{
|
||||
std::cerr << "ERR: Unterminated string\n";
|
||||
}
|
||||
|
||||
if (c == '\\')
|
||||
{
|
||||
c = file_.get();
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
case '\\':
|
||||
lexeme += c;
|
||||
break;
|
||||
case 'n':
|
||||
lexeme += '\n';
|
||||
break;
|
||||
case 't':
|
||||
lexeme += '\t';
|
||||
break;
|
||||
case '0':
|
||||
lexeme += '\0';
|
||||
break;
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
lexeme += process_octal_escape(file_, c);
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
lexeme += process_hex_escape(file_);
|
||||
break;
|
||||
case 'b':
|
||||
lexeme += '\b';
|
||||
break;
|
||||
case 'a':
|
||||
lexeme += '\a';
|
||||
break;
|
||||
case 'v':
|
||||
lexeme += '\v';
|
||||
break;
|
||||
case 'f':
|
||||
lexeme += '\f';
|
||||
break;
|
||||
default:
|
||||
std::cerr << "ERR: Improper escape sequence\n";
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
lexeme += c;
|
||||
}
|
||||
}
|
||||
|
||||
tokens_.emplace_back(TokenType::string, lexeme);
|
||||
|
||||
if (std::isalpha(file_.peek()))
|
||||
{
|
||||
std::cerr << "ERR: Literal operators are not yet supported\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (c == ';')
|
||||
{
|
||||
tokens_.emplace_back(TokenType::statement_term);
|
||||
}
|
||||
}
|
||||
}
|
||||
40
src/lexer/Lexer.hpp
Normal file
40
src/lexer/Lexer.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// Created by skythedragon on 6/24/25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
enum class TokenType
|
||||
{
|
||||
statement_term,
|
||||
exit,
|
||||
integer,
|
||||
number,
|
||||
string,
|
||||
op_plus,
|
||||
op_minus,
|
||||
op_multiply,
|
||||
op_divide
|
||||
};
|
||||
|
||||
struct Token {
|
||||
TokenType type;
|
||||
std::optional<std::string> lexeme;
|
||||
};
|
||||
|
||||
class Lexer {
|
||||
#ifdef TEST
|
||||
public:
|
||||
#endif
|
||||
std::ifstream file_;
|
||||
std::vector<Token> tokens_;
|
||||
|
||||
public:
|
||||
Lexer(std::ifstream& file);
|
||||
|
||||
void lex();
|
||||
};
|
||||
5
src/parser/Parser.cpp
Normal file
5
src/parser/Parser.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by skythedragon on 6/24/25.
|
||||
//
|
||||
|
||||
#include "Parser.hpp"
|
||||
18
src/parser/Parser.hpp
Normal file
18
src/parser/Parser.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Created by skythedragon on 6/24/25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <vector>
|
||||
|
||||
#include "../lexer/Lexer.hpp"
|
||||
|
||||
struct ParseNode {
|
||||
};
|
||||
|
||||
struct StatementNode : ParseNode {};
|
||||
|
||||
struct RootNode : ParseNode {};
|
||||
|
||||
class Parser {
|
||||
};
|
||||
84
src/tfc.cpp
Normal file
84
src/tfc.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "alib/colors.h"
|
||||
#include "lexer/Lexer.hpp"
|
||||
|
||||
using str = std::string;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::vector<str> args;
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
args.emplace_back(argv[i]);
|
||||
}
|
||||
|
||||
if (args.empty())
|
||||
{
|
||||
std::cerr << BOLDRED << "Error: " << WHITE << "no input file specified.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::ifstream input(args[0]);
|
||||
|
||||
Lexer lexer(input);
|
||||
|
||||
lexer.lex();
|
||||
|
||||
for (Token& token : lexer.tokens_)
|
||||
{
|
||||
str o;
|
||||
|
||||
switch (token.type)
|
||||
{
|
||||
case TokenType::exit:
|
||||
o = "exit";
|
||||
break;
|
||||
case TokenType::number:
|
||||
o = "number";
|
||||
break;
|
||||
case TokenType::integer:
|
||||
o = "integer";
|
||||
break;
|
||||
case TokenType::op_divide:
|
||||
o = "op_divide";
|
||||
break;
|
||||
case TokenType::string:
|
||||
o = "string";
|
||||
break;
|
||||
case TokenType::op_minus:
|
||||
o = "op_minus";
|
||||
break;
|
||||
case TokenType::op_multiply:
|
||||
o = "op_multiply";
|
||||
break;
|
||||
case TokenType::op_plus:
|
||||
o = "op_plus";
|
||||
break;
|
||||
case TokenType::statement_term:
|
||||
o = "statement_term";
|
||||
break;
|
||||
default:
|
||||
o = "error";
|
||||
break;
|
||||
}
|
||||
|
||||
std::cout << o;
|
||||
|
||||
if (token.lexeme)
|
||||
{
|
||||
std::cout << ": " << *token.lexeme;
|
||||
}
|
||||
|
||||
std::cout << '\n';
|
||||
}
|
||||
|
||||
std::cout << RESET;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user