(INIT): Project init

On-boarding will begin now...
This commit is contained in:
Hayden Hargreaves 2025-10-13 16:35:46 -07:00
parent 0c6f32df33
commit 7f6a3c6312
10 changed files with 326 additions and 1 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.o
/build
/build/*
parser

46
Makefile Normal file
View File

@ -0,0 +1,46 @@
# Define the C++ compiler and flags
CXX = g++
CXXFLAGS = -Wall -g
# Directories
BUILD_DIR = build
SRC_DIR = src
LIB_DIR = lib
# Executable name
TARGET = parser
SRC_FILES := $(wildcard $(SRC_DIR)/*.cpp)
LIB_FILES := $(wildcard $(LIB_DIR)/*.cpp)
ALL_SOURCES = $(SRC_FILES) $(LIB_FILES)
# Generate object file paths in the build directory
OBJECTS := $(patsubst %.cpp, $(BUILD_DIR)/%.o, $(notdir $(ALL_SOURCES)))
# Include directories
INCLUDES = -I$(LIB_DIR) -I$(SRC_DIR)
.PHONY: all clean test
all: $(BUILD_DIR) $(TARGET)
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
$(TARGET): $(OBJECTS)
$(CXX) $(CXXFLAGS) $(INCLUDES) $^ -o $@
$(BUILD_DIR)/main.o: $(SRC_DIR)/main.cpp $(LIB_DIR)/parser.h
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
$(BUILD_DIR)/parser.o: $(LIB_DIR)/parser.cpp $(LIB_DIR)/parser.h
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
test: all
./$(TARGET)
./$(TARGET) ' '
./$(TARGET) ./test/input.md
./$(TARGET) ./test/input.md ./test/output.html
clean:
rm -rf $(BUILD_DIR) $(TARGET)

View File

@ -1,3 +1,31 @@
# MarkdownToHtmlCompiler
This compiler will convert a Markdown file into an HTML output.
This compiler will convert a Markdown file into an HTML output.
### Notes
Recursive Descent Parser: This is the primary algorithm you'll use. It's a top-down parsing technique
where a set of recursive functions "descend" through the grammar of your simple Markdown language.
For example, a parse_document() function would call parse_line(), which in turn might call parse_bold_text()
or parse_italic_text(). This method is intuitive and easy to implement for a simple grammar.
Stack: A stack is essential for handling nested elements. For instance, if you allow bold text inside
italic text (_This is *bold and italic* text_), you can push the _ token onto the stack and then push
the * token. When you encounter the closing *, you check if the top of the stack matches. This ensures
that all tags are correctly opened and closed. Your presentation can visually demonstrate this process
with a stack diagram.
Hash Map or Map: A hash map (std::unordered_map) or a map (std::map) can be used to efficiently store
and retrieve the HTML equivalent for each Markdown tag. For example, you could map `#` to `<h1>` or "_"
to `<em>`. This provides O(1) average-case lookup time.
### Targets
- [-] Convert a .md file to an .html output
### Reaches
- [ ] Hot reload?

61
flake.lock generated Normal file
View File

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1760284886,
"narHash": "sha256-TK9Kr0BYBQ/1P5kAsnNQhmWWKgmZXwUQr4ZMjCzWf2c=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "cf3f5c4def3c7b5f1fc012b3d839575dbe552d43",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

42
flake.nix Normal file
View File

@ -0,0 +1,42 @@
{
description = "Blank development flake. Adjust as needed";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
in
{
# Define the development shell.
# When you run `nix develop` (or direnv activates), you'll enter this shell.
devShells.default = pkgs.mkShell {
# List all the development tools you need available in this shell's PATH.
packages = with pkgs; [
gcc
gdb
stdenv
];
# Define the shell that will be executed.
# Here, we explicitly use zsh.
# Note: pkgs.zsh needs to be included in `packages` or `nativeBuildInputs`
# for it to be found in the shell's environment. `inherit pkgs.zsh;` is concise.
inherit (pkgs) zsh;
# Environment variables and commands to run when the shell starts.
shellHook = ''
# Add any exports, hooks, aliases, or anything else here
# Exec zsh to replace the current shell process with zsh.
# This ensures your prompt and zsh configurations load correctly.
exec zsh
'';
};
}
);
}

43
lib/parser.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "./parser.h"
#include <cctype>
#include <stdexcept>
using std::string;
void removeWhitespace(string &input) {
size_t end = input.find_last_not_of(" \t\n\r\f\v");
if (end != std::string::npos) {
input.erase(end + 1);
} else {
input.clear(); // String contains only whitespace
}
size_t start = input.find_first_not_of(" \t\n\r\f\v");
if (start != std::string::npos) {
input.erase(0, start);
} else {
input.clear(); // String contains only whitespace
}
}
Parser::Parser(string input_file_path, string output_file_path) {
removeWhitespace(input_file_path);
removeWhitespace(output_file_path);
if (input_file_path == "") {
throw std::runtime_error("input_file_path cannot be empty");
}
this->input_file_path = input_file_path;
// NOTE: If the user does not provide an output file, then we should construct
// one using the input file with .md swapped with the extension.
if (output_file_path == "") {
std::cout << "CLEANING" << std::endl;
int ext_idx = input_file_path.find_last_of('.');
string output_cleaned = input_file_path.substr(0, ext_idx) + ".html";
this->output_file_path = output_cleaned;
} else {
this->output_file_path = output_file_path;
}
}

21
lib/parser.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef PARSER_H
#define PARSER_H
#include <iostream>
#include <string>
class Parser {
private:
std::string input_file_path;
std::string output_file_path;
public:
Parser(std::string input_file_path, std::string output_file_path = "");
inline void Print() {
std::cout << this->input_file_path << " -> " << this->output_file_path
<< std::endl;
}
};
#endif

25
src/main.cpp Normal file
View File

@ -0,0 +1,25 @@
#include "../lib/parser.h"
#include <stdexcept>
int main(int argc, char **argv) {
if (argc <= 1) {
std::cerr << "Usage: <input_file> <?output_file>" << std::endl;
return 0; // TODO: Should return 1?
}
try {
if (argc >= 3) {
Parser p(argv[1], argv[2]);
p.Print();
} else {
Parser p(argv[1]);
p.Print();
}
} catch (const std::runtime_error &e) {
std::cout << "Caught an error: " << e.what() << std::endl;
} catch (...) {
std::cout << "Caught an error: UNKNOWN" << std::endl;
}
return 0;
}

38
syntax.md Normal file
View File

@ -0,0 +1,38 @@
Reference [here](https://www.markdownguide.org/basic-syntax/)
Headings, h# tags
# Header Level 1 -> <h1> Content </h1>
## Header Level 2 -> <h2> Content </h2>
### Header Level 3 -> <h3> Content </h3>
#### Header Level 4 -> <h4> Content </h4>
##### Header Level 5 -> <h5> Content </h5>
###### Header Level 6 -> <h6> Content </h6>
Alternate syntax (n number of =/-)
Header Level 1 -> <h1> Content </h1>
================
Header Level 2 -> <h2> Content </h2>
----------------
Paragraph tags
Hello world -> <p> Hello world </p>
This is also
a paragraph -> <p> this is also a paragraph regardless </p>
regardless
However
this is a break, because it ends with two spaces -> <p> However <br> this is a break, because it ends with two spaces </p>
Double returns also
yield line breaks -> <p> Double returns also <br> yield line breaks </p>

17
test/input.md Normal file
View File

@ -0,0 +1,17 @@
# Hello world in an h1 tag
## This is a h2 tag
### h3
#### h4
##### h5
###### h6