From 64d3acd00ebdadace5f4297fe3b49bb38c0248da Mon Sep 17 00:00:00 2001 From: WhyIsEvery4thYearAlwaysBad Date: Sun, 4 Apr 2021 09:19:04 -0500 Subject: [PATCH 01/11] Proper include file guard. --- src/commandmenu.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commandmenu.hpp b/src/commandmenu.hpp index d74cd5a..6fca63b 100644 --- a/src/commandmenu.hpp +++ b/src/commandmenu.hpp @@ -1,10 +1,10 @@ -#ifndef PAGE_HPP -#define PAGE_HPP +#ifndef COMMANDMENU_HPP +#define COMMANDMENU_HPP #include #include #include -#include "binds.hpp" #include "compiler.hpp" +#include "bind.hpp" struct CommandMenu { std::string sRawName, sName; From 82a277e205f21fc0ca96514a5988e6788c11602f Mon Sep 17 00:00:00 2001 From: WhyIsEvery4thYearAlwaysBad Date: Thu, 8 Apr 2021 17:29:03 -0500 Subject: [PATCH 02/11] Finished refactoring the code for now. --- compile.cmd | 2 +- compile.sh | 6 +- src/{binds.cpp => bind.cpp} | 4 +- src/{binds.hpp => bind.hpp} | 0 src/commandmenu.cpp | 1 + src/compiler.cpp | 281 ++++------------------------------ src/compiler.hpp | 10 +- src/lex.cpp | 212 +++++++++++++++++++++++++ src/lex.hpp | 7 + src/main.cpp | 9 +- src/{tokens.cpp => token.cpp} | 2 +- src/{tokens.hpp => token.hpp} | 0 12 files changed, 265 insertions(+), 269 deletions(-) rename src/{binds.cpp => bind.cpp} (98%) rename src/{binds.hpp => bind.hpp} (100%) create mode 100644 src/lex.cpp create mode 100644 src/lex.hpp rename src/{tokens.cpp => token.cpp} (93%) rename src/{tokens.hpp => token.hpp} (100%) diff --git a/compile.cmd b/compile.cmd index 334d167..fb371bb 100644 --- a/compile.cmd +++ b/compile.cmd @@ -1,5 +1,5 @@ @echo off -pushd C:\Users\Owner\Documents\Projects\VoicemenuGenerator\src +pushd C:\Users\Owner\Documents\Projects\CmdMenuGenerator\src g++ -m32 binds.cpp commandmenu.cpp launchoptions.cpp compiler.cpp tokens.cpp main.cpp -o ../cvm_generate_x32.exe -std=c++2a -Wall if NOT %%ERRORLEVEL%% EQU 0 ( pause diff --git a/compile.sh b/compile.sh index 6811c9c..b89817a 100644 --- a/compile.sh +++ b/compile.sh @@ -1,10 +1,10 @@ -pushd src -g++ -m32 binds.cpp commandmenu.cpp launchoptions.cpp compiler.cpp tokens.cpp main.cpp -o ../cvm_generate_x32.exe -std=c++2a -Wall +pushd C:/Users/Owner/Documents/Projects/CmdMenuGenerator/src +g++ -g -m32 * -o ../cmg-x32.exe -std=c++2a -Wall if [ ! $? -eq 0 ] then read -n1 -r -p "Error(s) have occurred here! Press a key to continue." fi -g++ -m64 binds.cpp commandmenu.cpp launchoptions.cpp compiler.cpp tokens.cpp main.cpp -o ../cvm_generate_x64.exe -std=c++2a -Wall +g++ -g -m64 * -o ../cmg-x64.exe -std=c++2a -Wall if [ ! $? -eq 0 ] then read -n1 -r -p "Error(s) have occurred here! Press a key to continue." diff --git a/src/binds.cpp b/src/bind.cpp similarity index 98% rename from src/binds.cpp rename to src/bind.cpp index 74cd433..18d77d7 100644 --- a/src/binds.cpp +++ b/src/bind.cpp @@ -1,5 +1,6 @@ -#include "binds.hpp" +#include "bind.hpp" #include "compiler.hpp" +#include "lex.hpp" #include extern std::map KVMap; Bind::Bind() {} @@ -28,6 +29,7 @@ Bind::Bind(const unsigned char& p_cKey, const Parser::BindToken& p_Token) if (p_Token.bNoExit==true) CmdStrContainer.push_back(p_Token.sCmdStr); else CmdStrContainer.push_back("cmenu.exitmenu; cmenu.on_cmenu_exit; "+p_Token.sCmdStr); } + Bind::Bind(const unsigned char& p_cKey, const Parser::ToggleBindToken& p_Token) : bToggleBind(true), cKey(p_cKey) { for (unsigned short i=0; i < p_Token.ToggleStates; i++) { diff --git a/src/binds.hpp b/src/bind.hpp similarity index 100% rename from src/binds.hpp rename to src/bind.hpp diff --git a/src/commandmenu.cpp b/src/commandmenu.cpp index 057a6b2..ddde4bf 100644 --- a/src/commandmenu.cpp +++ b/src/commandmenu.cpp @@ -1,5 +1,6 @@ #include "commandmenu.hpp" #include "compiler.hpp" +#include "lex.hpp" CommandMenu::CommandMenu() {} diff --git a/src/compiler.cpp b/src/compiler.cpp index 7e5133e..97f12b4 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -1,238 +1,21 @@ -#include "Tokens.hpp" -#include "binds.hpp" -#include "commandmenu.hpp" -#include "compiler.hpp" #include #include #include #include #include -std::size_t iLineNum=1u; -std::size_t iLineColumn=1u; +#include "compiler.hpp" +#include "lex.hpp" +#include "token.hpp" +#include "bind.hpp" +#include "commandmenu.hpp" + extern std::map KVMap; -#define Error(error) ErrorTokens.push_back(Token(0u,0u,TokenType::COMPILER_ERROR,error)) std::deque TokenContainer; std::deque ErrorTokens; std::deque CMenuTokens; extern std::deque CMenuContainer; // Made in main.cpp -// Convert to a safer string format for file and caption names. -std::string formatRaw(std::string p_sInStr) { - for (unsigned long long i=0; i < p_sInStr.length(); i++) { - if (p_sInStr.at(i)=='<' && p_sInStr.find('>',i)!=std::string::npos) { - p_sInStr.erase(i,(p_sInStr.find('>',i+1)-i)+1); - if (i>0) i--; - } - // remove punctuation - if (ispunct(p_sInStr.at(i))) { - p_sInStr.erase(i,1); - i--; - continue; - } - // and non-ascii characters - if (i0) TokenContainer.back().sValue.shrink_to_fit(); - // EOF Token - if (i==p_sInStr.length()-1) { - TokenContainer.push_back(Token(p_sInStr.length()-1,iLineNum,TokenType::END_OF_FILE,"")); - TokenContainer.back().sValue.shrink_to_fit(); - break; - } - // Nonterminal - if (IsIdentChar(p_sInStr.at(i))) { - TokenContainer.push_back(Token(iLineColumn,iLineNum,TokenType::IDENTIFIER,"")); - while (IsIdentChar(p_sInStr.at(i))) - { - TokenContainer.back().sValue.push_back(p_sInStr.at(i)); - i++; - iLineColumn++; - } - // Check for terminals. - if (TokenContainer.back().sValue=="TOGGLE") TokenContainer.back().Type=TokenType::TOGGLE; - else if (TokenContainer.back().sValue=="BIND") TokenContainer.back().Type=TokenType::BIND; - else if (TokenContainer.back().sValue=="NOEXIT") TokenContainer.back().Type=TokenType::NOEXIT; - else if (TokenContainer.back().sValue=="NOFORMAT") TokenContainer.back().Type=TokenType::NOFORMAT; - continue; - } - switch (p_sInStr.at(i)) - { - // comments - case '/': - // Line comments - if (p_sInStr.at(i+1)=='/') { - for (auto t=p_sInStr.begin()+i; t!=p_sInStr.end(); t++, i++) { - if (*t=='\t') iLineColumn+=5-(iLineColumn%4==0 ? 4 : iLineColumn%4); - else iLineColumn++; - if (*t=='\n' || *t=='\r') break; - } - } - /* Block comments */ - else if (p_sInStr.at(i+1)=='*') { // - std::size_t tempi=i, templinecolumn=iLineColumn, templinenumber=iLineNum; - for (auto t=p_sInStr.begin()+i; t!=p_sInStr.end(); t++, tempi++) { - if (*t=='\t') templinecolumn+=5-(iLineColumn%4==0 ? 4 : iLineColumn%4); - else templinecolumn++; - if (*t=='\n') { - if (*(t-1)!='\r') templinecolumn=1u; - templinenumber++; - } - else if (*t=='\r') { - templinecolumn=1u; - if (*(t+1)!='\n') templinenumber++; - } - if (*t=='*' && *(t+1)=='/') { - i=tempi+2; - iLineColumn=templinecolumn+2; - iLineNum=templinenumber+2; - break; - } - if (t==p_sInStr.end()-1) { - Error("error: Unclosed comment. ("+std::to_string(iLineNum)+':'+std::to_string(iLineColumn)+')'); - i=tempi; - break; - } - } - } - else { - TokenContainer.push_back(Token(iLineColumn,iLineNum,TokenType::UNDEFINED,"/")); - iLineColumn++; - i++; - } - break; - // strings - case '\"': - { - std::size_t tempcol=iLineColumn,templn=iLineNum; - // New lines or carriage returns cannot be in strings. (I don't mean the '\r' or '\n' character.) - for (i++, iLineColumn++; i < p_sInStr.length(); i++, iLineColumn++) { - if (p_sInStr.at(i)=='\r') { - Error("error: Missing a quote at ("); - ErrorTokens.back().iLineNum=iLineNum; - ErrorTokens.back().iLineColumn=iLineColumn; - ErrorTokens.back().sValue+=ErrorTokens.back().GetFileLoc()+")"; - // - TokenContainer.push_back(Token(iLineColumn,iLineNum,TokenType::STRING,"")); - t_sStrTemp=""; - iLineColumn=1u; - if (p_sInStr.at(i+1)!='\n') { - iLineNum++; - i++; - } - break; - } - else if (p_sInStr.at(i)=='\n') { - Error("error: Missing a quote at ("); - ErrorTokens.back().iLineNum=iLineNum; - ErrorTokens.back().iLineColumn=iLineColumn; - ErrorTokens.back().sValue+=ErrorTokens.back().GetFileLoc()+")"; - // - TokenContainer.push_back(Token(iLineColumn,iLineNum,TokenType::STRING,"")); - t_sStrTemp=""; - iLineNum++; - if (p_sInStr.at(i-1)!='\r') { - iLineColumn=1u; - i++; - } - break; - } - else if (i==p_sInStr.length()-1){ - Error("error: Missing a quote at ("); - ErrorTokens.back().sValue+=ErrorTokens.back().GetFileLoc()+")"; - t_sStrTemp=""; - break; - } - else if (p_sInStr.at(i)=='\"') { - TokenContainer.push_back(Token(tempcol,templn,TokenType::STRING,t_sStrTemp)); - t_sStrTemp=""; - break; - } - else { - if (p_sInStr.at(i)=='\t') iLineColumn+=5-(iLineColumn%4==0 ? 4 : iLineColumn%4); - t_sStrTemp+=p_sInStr.at(i); - } - } - i++; // Starts at the ending quote if this doesn't exist. - iLineColumn++; - } - break; - //terminals - case '=': - TokenContainer.push_back(Token(iLineColumn,iLineNum,TokenType::EQUALS,"=")); - i++; - iLineColumn++; - break; - case '|': - TokenContainer.push_back(Token(iLineColumn,iLineNum,TokenType::VBAR,"|")); - i++; - iLineColumn++; - break; - case '{': - TokenContainer.push_back(Token(iLineColumn,iLineNum,TokenType::LCBRACKET,"{")); - i++; - iLineColumn++; - break; - case '}': - TokenContainer.push_back(Token(iLineColumn,iLineNum,TokenType::RCBRACKET,"}")); - i++; - iLineColumn++; - break; - //spaces and colon - case '\t': - iLineColumn+=5-(iLineColumn%4==0 ? 4 : iLineColumn%4); - i++; - break; - case ' ': - iLineColumn++; - i++; - break; - case '\r': - iLineColumn=1u; - if (i+1==p_sInStr.length() || p_sInStr.at(i+1)!='\n') iLineNum++; - i++; - break; - case '\v': - i++; - iLineNum++; - break; - case '\n': - iLineNum++; - if (i>0 && p_sInStr.at(i-1)!='\r') iLineColumn=1u; - i++; - break; - default: - TokenContainer.push_back(Token(iLineColumn,iLineNum,TokenType::UNDEFINED,"")); - TokenContainer.back().sValue.push_back(p_sInStr.at(i)); - iLineColumn++; - i++; - break; - } - } - if (ErrorTokens.size()>=1) bErrorsFound=true; - return !bErrorsFound; -} + namespace Parser { unsigned int depth=0u; bool bEOFFound=false, bErrorsFound=false; @@ -241,12 +24,12 @@ namespace Parser { for (auto token=TokenContainer.begin(); token!=TokenContainer.end(); ) { switch (token->Type) { case TokenType::NOEXIT: - if (bNoExit==true) Error("error: Duplicate modifier \"NOEXIT\". ("+token->GetFileLoc()+')'); + if (bNoExit==true) TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Duplicate modifier \"NOEXIT\".")); else bNoExit=true; token++; break; case TokenType::NOFORMAT: - if (bFormatted==false) Error("error: Duplicate modifier \"NOFORMAT\". ("+token->GetFileLoc()+')'); + if (bFormatted==false) TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Duplicate modifier \"NOFORMAT\".")); else bFormatted=false; token++; break; @@ -256,9 +39,9 @@ namespace Parser { std::string cmdlist[MAX_TOGGLE_STATES]; unsigned short i=1; if (depth<=0) - Error("error: Toggle bind must be set in a command menu. ("+token->GetFileLoc()+')'); + TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Toggle bind must be set in a command menu.")); if ((token+i)->Type!=TokenType::BIND) - Error("Expected \'BIND\' ("+(token+i)->GetFileLoc()+")"); + TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Expected \'BIND\' keyword here.")); else i++; while ((token+i)->Type==TokenType::STRING) { @@ -267,9 +50,9 @@ namespace Parser { i++; } if (i-1<=1 || i % 2!=0) // Even amount of strings indicate that the toggle bind has names and cmdstrs - Error("error: Expected string! ("+(token+i)->GetFileLoc()+")"); + TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Expected string here.")); if ((token+i)->Type!=TokenType::VBAR) - Error("error: Expected '|' ("+(token+i-1)->GetFileLoc()+")"); + TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+"error: Expected '|'.")); CMenuTokens.push_back(new Parser::ToggleBindToken(namelist,cmdlist,static_cast((i-2)/2),bNoExit,bFormatted)); if (bNoExit==true) bNoExit=false; token+=i; @@ -279,17 +62,17 @@ namespace Parser { { unsigned short i=1u; if (depth<=0) - Error("error: Bind must be set in a commandmenu. ("+token->GetFileLoc()+')'); + TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Bind must be set in a command menu.")); if ((token+i)->Type!=TokenType::STRING) - Error("error: Expected string. ("+(token+i)->GetFileLoc()+")"); + TokenContainer.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected string.")); else { i++; if ((token+i)->Type!=TokenType::STRING) - Error("error: Expected string. ("+(token+i)->GetFileLoc()+")"); + TokenContainer.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected string.")); else i++; } if ((token+i)->Type!=TokenType::VBAR) - Error("error: Expected '|' ("+(token+i)->GetFileLoc()+")"); + TokenContainer.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected '|'.")); else i++; CMenuTokens.push_back(new Parser::BindToken((token+1)->sValue, (token+2)->sValue,bNoExit,bFormatted)); bNoExit=false, bFormatted=true; @@ -300,9 +83,9 @@ namespace Parser { { unsigned short i=1u; if ((token+i)->Type!=TokenType::LCBRACKET) - Error("error: Expected '{' ("+(token+i)->GetFileLoc()+")"); + TokenContainer.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected '{' here.")); else if (bNoExit==true) { - Error("error: Expected a bind. ("+token->GetFileLoc()+')'); + TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Expected a bind.")); bNoExit=false; } CMenuTokens.push_back(new Parser::CMenuToken(token->sValue,bFormatted)); @@ -314,19 +97,13 @@ namespace Parser { case TokenType::IDENTIFIER: // Check for set keymaps { unsigned short i=1u; - // Maybe they were trying to make a commandmenu… - if ((token+i)->Type==TokenType::LCBRACKET) { - token++; - break; - }; - if ((token+i)->Type!=TokenType::EQUALS) { - Error("error: Expected '='! ("+(token+i)->GetFileLoc()+")"); + TokenContainer.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected a '=' here.")); TokenContainer.insert(token+i,Token((token+i)->iLineColumn,(token+i)->iLineNum,TokenType::EQUALS,"=")); } if ((token+i+1)->Type!=TokenType::LCBRACKET) i++; if ((token+i)->Type!=TokenType::STRING || (token+i+1)->Type==TokenType::LCBRACKET) { - Error("error: Expected string! ("+(token+i)->GetFileLoc()+")"); + TokenContainer.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected a string here.")); TokenContainer.insert(token+i,Token((token+i)->iLineColumn,(token+i)->iLineNum,TokenType::STRING,"")); } if ((token+i+1)->Type!=TokenType::LCBRACKET) i++; @@ -337,7 +114,7 @@ namespace Parser { case TokenType::LCBRACKET: depth++; if (token>TokenContainer.begin() && (token-1)->Type!=TokenType::STRING) { - Error("error: Expected string! ("+(token-1)->GetFileLoc()+")"); + TokenContainer.push_back(Token((token-1)->iLineNum,(token-1)->iLineColumn,TokenType::COMPILER_ERROR,(token-1)->GetFileLoc()+": error: Expected a string here.")); depth--; } token++; @@ -345,10 +122,10 @@ namespace Parser { case TokenType::RCBRACKET: depth--; if (depth==UINT32_MAX) { - Error("error: Stray '}' ("+token->GetFileLoc()+")"); + TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Stray '}'")); depth++; } - CMenuTokens.push_back(new Parser::PageEndToken()); + CMenuTokens.push_back(new Parser::CMenuEndToken()); token++; break; case TokenType::END_OF_FILE: @@ -356,16 +133,18 @@ namespace Parser { token=TokenContainer.end(); break; case TokenType::UNDEFINED: - Error("error: Unrecognized token '"+token->sValue+"' ("+token->GetFileLoc()+")"); + TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Unrecognized character '"+token->sValue+"'.")); token++; break; + case TokenType::COMPILER_ERROR: + std::cout<sValue<<'\n'; + break; default: token++; - break; - } + break; + } } if (bEOFFound==false) std::cout<<"warning: EOF not found!\n"; - if (ErrorTokens.size()>=1) bErrorsFound=true; return !bErrorsFound; } } diff --git a/src/compiler.hpp b/src/compiler.hpp index 5e7cf00..47bc580 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -3,11 +3,7 @@ #define MAX_TOGGLE_STATES 512 #include #include -#include "Tokens.hpp" -// Convert to a safer string format for file and caption names. (Yes the duplicate input string is intentional.) -std::string formatRaw(std::string p_sInStr); -// Tokenize any string into needed Tokens for parsing. -bool Tokenize(const std::string& str); +#include "token.hpp" void ParseMenuTokens(unsigned short& p_iBindCount); namespace Parser { // For handling multi Tokens. @@ -66,8 +62,8 @@ namespace Parser { Type=CMenuTokenType::DECLARE_CMENU; } }; - struct PageEndToken : public MenuToken { - PageEndToken() { + struct CMenuEndToken : public MenuToken { + CMenuEndToken() { Type=CMenuTokenType::END_CMENU; } }; diff --git a/src/lex.cpp b/src/lex.cpp new file mode 100644 index 0000000..d4c1f69 --- /dev/null +++ b/src/lex.cpp @@ -0,0 +1,212 @@ +#include +#include +#include "lex.hpp" +#include "compiler.hpp" +#include "token.hpp" + +std::size_t iLineNum=1u; +std::size_t iLineColumn=1u; + +extern std::deque TokenContainer; +extern std::deque CMenuTokens; + +// Convert to a safer string format for file and caption names. +std::string formatRaw(std::string p_sInStr) { + for (unsigned long long i=0; i < p_sInStr.length(); i++) { + if (p_sInStr.at(i)=='<' && p_sInStr.find('>',i)!=std::string::npos) { + p_sInStr.erase(i,(p_sInStr.find('>',i+1)-i)+1); + if (i>0) i--; + } + // remove punctuation + if (ispunct(p_sInStr.at(i))) { + p_sInStr.erase(i,1); + i--; + continue; + } + // and non-ascii characters + if (i0) TokenContainer.back().sValue.shrink_to_fit(); + // EOF Token + if (i == p_sInStr.length() - 1) { + TokenContainer.push_back(Token(iLineNum,p_sInStr.length()-1,TokenType::END_OF_FILE,"")); + TokenContainer.back().sValue.shrink_to_fit(); + break; + } + // Nonterminal + if (IsIdentChar(p_sInStr.at(i))) { + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::IDENTIFIER,"")); + while (IsIdentChar(p_sInStr.at(i))) + { + TokenContainer.back().sValue.push_back(p_sInStr.at(i)); + i++; + iLineColumn++; + } + // Check for terminals. + if (TokenContainer.back().sValue=="TOGGLE") TokenContainer.back().Type=TokenType::TOGGLE; + else if (TokenContainer.back().sValue=="BIND") TokenContainer.back().Type=TokenType::BIND; + else if (TokenContainer.back().sValue=="NOEXIT") TokenContainer.back().Type=TokenType::NOEXIT; + else if (TokenContainer.back().sValue=="NOFORMAT") TokenContainer.back().Type=TokenType::NOFORMAT; + continue; + } + switch (p_sInStr.at(i)) + { + // comments + case '/': + // Line comments + if (p_sInStr.at(i+1)=='/') { + for (auto t=p_sInStr.begin()+i; t!=p_sInStr.end(); t++, i++) { + if (*t=='\t') iLineColumn += 4 - (iLineColumn % 4); + else iLineColumn++; + if (*t=='\n' || *t=='\r') break; + } + } + /* Block comments */ + else if (p_sInStr.at(i+1)=='*') { // + bInBlockComment=true; + i+=2; + iLineColumn+=2; + } + else { + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::UNDEFINED,"/")); + iLineColumn++; + i++; + } + break; + // strings + case '\"': + { + std::size_t tempcol=iLineColumn,templn=iLineNum; + // New lines or carriage returns cannot be in strings. (I don't mean the '\r' or '\n' character.) + for (i++, iLineColumn++; i < p_sInStr.length(); i++, iLineColumn++) { + if (p_sInStr.at(i)=='\r') { + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::COMPILER_ERROR,std::to_string(iLineNum)+':'+std::to_string(iLineColumn)+": error: Ending '\"' is missing.")); + // + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::STRING,"")); + t_sStrTemp=""; + iLineColumn=1u; + if (p_sInStr.at(i+1)!='\n') { + iLineNum++; + i++; + } + break; + } + else if (p_sInStr.at(i)=='\n') { + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::COMPILER_ERROR,std::to_string(iLineNum)+':'+std::to_string(iLineColumn)+": error: Ending '\"' is missing.")); + // + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::STRING,"")); + t_sStrTemp=""; + iLineNum++; + if (p_sInStr.at(i-1)!='\r') { + iLineColumn=1u; + i++; + } + break; + } + else if (i==p_sInStr.length()-1){ + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::COMPILER_ERROR,std::to_string(iLineNum)+':'+std::to_string(iLineColumn)+": error: Ending '\"' is missing.")); + t_sStrTemp=""; + break; + } + else if (p_sInStr.at(i)=='\"') { + TokenContainer.push_back(Token(tempcol,templn,TokenType::STRING,t_sStrTemp)); + t_sStrTemp=""; + break; + } + else { + if (p_sInStr.at(i)=='\t') iLineColumn += 4 - (iLineColumn % 4); + t_sStrTemp+=p_sInStr.at(i); + } + } + i++; // Starts at the ending quote if this doesn't exist. + iLineColumn++; + } + break; + //terminals + case '=': + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::EQUALS,"=")); + i++; + iLineColumn++; + break; + case '|': + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::VBAR,"|")); + i++; + iLineColumn++; + break; + case '{': + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::LCBRACKET,"{")); + i++; + iLineColumn++; + break; + case '}': + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::RCBRACKET,"}")); + i++; + iLineColumn++; + break; + //spaces and colon + case '\t': + iLineColumn += 4 - (iLineColumn % 4); + i++; + break; + case ' ': + iLineColumn++; + i++; + break; + case '\r': + iLineColumn=1u; + if (i+1==p_sInStr.length() || p_sInStr.at(i+1)!='\n') iLineNum++; + i++; + break; + case '\v': + i++; + iLineNum++; + break; + case '\n': + iLineNum++; + if (i>0 && p_sInStr.at(i-1)!='\r') iLineColumn=1u; + i++; + break; + default: + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::UNDEFINED,"")); + TokenContainer.back().sValue.push_back(p_sInStr.at(i)); + iLineColumn++; + i++; + break; + } + } + return !bErrorsFound; + } +} \ No newline at end of file diff --git a/src/lex.hpp b/src/lex.hpp new file mode 100644 index 0000000..eb026b1 --- /dev/null +++ b/src/lex.hpp @@ -0,0 +1,7 @@ +#include +// Convert to a safer string format for file and caption names. (Yes the duplicate input string is intentional.) +std::string formatRaw(std::string p_sInStr); +namespace Lexer { + // Tokenize any string into needed Tokens for parsing. + bool Tokenize(const std::string& str); +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 3a019e2..19a69fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,7 +7,8 @@ #include #include #include -#include "Tokens.hpp" +#include "lex.hpp" +#include "token.hpp" #include "commandmenu.hpp" #include "compiler.hpp" #include "launchoptions.hpp" @@ -35,10 +36,8 @@ int main(int argc, char** argv) { InFileContent+=Line+'\n'; } // If tokenization and parsing process failed, then error out and return. - if (!Tokenize(InFileContent) || !Parser::ParseTokens()) { - for (auto& e : ErrorTokens) { - std::cout< #include diff --git a/src/tokens.hpp b/src/token.hpp similarity index 100% rename from src/tokens.hpp rename to src/token.hpp From 62278a2708ec66e027e3991939d248f46b9cfcfe Mon Sep 17 00:00:00 2001 From: WhyIsEvery4thYearAlwaysBad Date: Fri, 9 Apr 2021 22:28:15 -0500 Subject: [PATCH 03/11] Bundled Commit: * Fixed: Tokenizer function improperly ignore block comments. * Fixed: Tokenizer and Parser function not returning errors when there are errors. * Replaced consolemode KV with display KV. (Three values: "caption", "console", and "none") "display" keyvalue determines the type of display to use for binds. --- src/commandmenu.cpp | 16 ++- src/commandmenu.hpp | 8 +- src/compiler.cpp | 84 ++++++------ src/compiler.hpp | 2 +- src/lex.cpp | 312 +++++++++++++++++++++++++------------------- src/main.cpp | 174 +++++++++++++----------- src/token.hpp | 2 +- 7 files changed, 344 insertions(+), 254 deletions(-) diff --git a/src/commandmenu.cpp b/src/commandmenu.cpp index ddde4bf..a37913e 100644 --- a/src/commandmenu.cpp +++ b/src/commandmenu.cpp @@ -1,13 +1,25 @@ +#include #include "commandmenu.hpp" #include "compiler.hpp" #include "lex.hpp" +extern std::map KVMap; + CommandMenu::CommandMenu() {} CommandMenu::CommandMenu(const std::string& p_sName) - : sRawName(formatRaw(p_sName)), sName(p_sName) {} +: sRawName(formatRaw(p_sName)), sName(p_sName) { + if (KVMap["display"]=="caption") Display=CMenuDisplayType::CAPTIONS; + else if (KVMap["display"]=="console") Display=CMenuDisplayType::CONSOLE; + else if (KVMap["display"]=="none") Display=CMenuDisplayType::NONE; +} CommandMenu::CommandMenu(const std::string& p_sRawName, const std::string& p_sName) -: sRawName(p_sRawName), sName(p_sName) {} +: sRawName(p_sRawName), sName(p_sName) { + if (KVMap["display"]=="caption") Display=CMenuDisplayType::CAPTIONS; + else if (KVMap["display"]=="console") Display=CMenuDisplayType::CONSOLE; + else if (KVMap["display"]=="none") Display=CMenuDisplayType::NONE; + else Display=CMenuDisplayType::CAPTIONS; +} CommandMenu::~CommandMenu() {} \ No newline at end of file diff --git a/src/commandmenu.hpp b/src/commandmenu.hpp index 6fca63b..a0e2612 100644 --- a/src/commandmenu.hpp +++ b/src/commandmenu.hpp @@ -6,10 +6,16 @@ #include "compiler.hpp" #include "bind.hpp" +enum class CMenuDisplayType { + NONE=0, + CONSOLE, + CAPTIONS +}; + struct CommandMenu { std::string sRawName, sName; std::vector binds; - + CMenuDisplayType Display; CommandMenu(); CommandMenu(const std::string& p_sName); CommandMenu(const std::string& p_sRawName, const std::string& p_sName); diff --git a/src/compiler.cpp b/src/compiler.cpp index 97f12b4..59c055f 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -24,36 +24,36 @@ namespace Parser { for (auto token=TokenContainer.begin(); token!=TokenContainer.end(); ) { switch (token->Type) { case TokenType::NOEXIT: - if (bNoExit==true) TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Duplicate modifier \"NOEXIT\".")); + if (bNoExit==true) ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Duplicate modifier \"NOEXIT\".")); else bNoExit=true; token++; break; case TokenType::NOFORMAT: - if (bFormatted==false) TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Duplicate modifier \"NOFORMAT\".")); + if (bFormatted==false) ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Duplicate modifier \"NOFORMAT\".")); else bFormatted=false; token++; break; case TokenType::TOGGLE: { // Check for toggle bind. - std::string namelist[MAX_TOGGLE_STATES]; - std::string cmdlist[MAX_TOGGLE_STATES]; + std::string NameList[MAX_TOGGLE_STATES]; + std::string CmdList[MAX_TOGGLE_STATES]; unsigned short i=1; if (depth<=0) - TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Toggle bind must be set in a command menu.")); + ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Toggle bind must be set in a command menu.")); if ((token+i)->Type!=TokenType::BIND) - TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Expected \'BIND\' keyword here.")); + ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Expected \'BIND\' keyword here.")); else i++; while ((token+i)->Type==TokenType::STRING) { - if (i % 2 == 0) namelist[(i-2)/2]=(token+i)->sValue; - else if (i % 2 == 1) cmdlist[(i-2)/2]=(token+i)->sValue; + if (i % 2 == 0) NameList[(i-2)/2]=(token+i)->sValue; + else if (i % 2 == 1) CmdList[(i-2)/2]=(token+i)->sValue; i++; } if (i-1<=1 || i % 2!=0) // Even amount of strings indicate that the toggle bind has names and cmdstrs - TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Expected string here.")); + ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Expected string here.")); if ((token+i)->Type!=TokenType::VBAR) - TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+"error: Expected '|'.")); - CMenuTokens.push_back(new Parser::ToggleBindToken(namelist,cmdlist,static_cast((i-2)/2),bNoExit,bFormatted)); + ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+"error: Expected '|'.")); + if (!bErrorsFound) CMenuTokens.push_back(new Parser::ToggleBindToken(NameList,CmdList,static_cast((i-2)/2),bNoExit,bFormatted)); if (bNoExit==true) bNoExit=false; token+=i; } @@ -62,19 +62,19 @@ namespace Parser { { unsigned short i=1u; if (depth<=0) - TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Bind must be set in a command menu.")); + ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Bind must be set in a command menu.")); if ((token+i)->Type!=TokenType::STRING) - TokenContainer.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected string.")); + ErrorTokens.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected a string.")); else { i++; if ((token+i)->Type!=TokenType::STRING) - TokenContainer.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected string.")); + ErrorTokens.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected a string.")); else i++; } if ((token+i)->Type!=TokenType::VBAR) - TokenContainer.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected '|'.")); + ErrorTokens.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected '|'.")); else i++; - CMenuTokens.push_back(new Parser::BindToken((token+1)->sValue, (token+2)->sValue,bNoExit,bFormatted)); + if (!bErrorsFound) CMenuTokens.push_back(new Parser::BindToken((token+1)->sValue, (token+2)->sValue,bNoExit,bFormatted)); bNoExit=false, bFormatted=true; token+=i; } @@ -83,12 +83,12 @@ namespace Parser { { unsigned short i=1u; if ((token+i)->Type!=TokenType::LCBRACKET) - TokenContainer.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected '{' here.")); + ErrorTokens.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected '{' here.")); else if (bNoExit==true) { - TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Expected a bind.")); + ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Expected a bind.")); bNoExit=false; } - CMenuTokens.push_back(new Parser::CMenuToken(token->sValue,bFormatted)); + if (!bErrorsFound) CMenuTokens.push_back(new Parser::CMenuToken(token->sValue,bFormatted)); bFormatted=true; token+=i; depth++; @@ -98,23 +98,21 @@ namespace Parser { { unsigned short i=1u; if ((token+i)->Type!=TokenType::EQUALS) { - TokenContainer.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected a '=' here.")); - TokenContainer.insert(token+i,Token((token+i)->iLineColumn,(token+i)->iLineNum,TokenType::EQUALS,"=")); - } - if ((token+i+1)->Type!=TokenType::LCBRACKET) i++; - if ((token+i)->Type!=TokenType::STRING || (token+i+1)->Type==TokenType::LCBRACKET) { - TokenContainer.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected a string here.")); - TokenContainer.insert(token+i,Token((token+i)->iLineColumn,(token+i)->iLineNum,TokenType::STRING,"")); + ErrorTokens.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected a '=' here.")); + } + else i++; + if ((token+i)->Type!=TokenType::STRING) { + ErrorTokens.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected a string here.")); } - if ((token+i+1)->Type!=TokenType::LCBRACKET) i++; - CMenuTokens.push_back(new Parser::KVToken(token->sValue,(token+2)->sValue)); + else i++; + if (!bErrorsFound) CMenuTokens.push_back(new Parser::KVToken(token->sValue,(token+2)->sValue)); token+=i; } break; case TokenType::LCBRACKET: depth++; if (token>TokenContainer.begin() && (token-1)->Type!=TokenType::STRING) { - TokenContainer.push_back(Token((token-1)->iLineNum,(token-1)->iLineColumn,TokenType::COMPILER_ERROR,(token-1)->GetFileLoc()+": error: Expected a string here.")); + ErrorTokens.push_back(Token((token-1)->iLineNum,(token-1)->iLineColumn,TokenType::COMPILER_ERROR,(token-1)->GetFileLoc()+": error: Expected a string here.")); depth--; } token++; @@ -122,10 +120,10 @@ namespace Parser { case TokenType::RCBRACKET: depth--; if (depth==UINT32_MAX) { - TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Stray '}'")); + ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Stray '}'")); depth++; } - CMenuTokens.push_back(new Parser::CMenuEndToken()); + if (!bErrorsFound) CMenuTokens.push_back(new Parser::CMenuEndToken()); token++; break; case TokenType::END_OF_FILE: @@ -133,24 +131,29 @@ namespace Parser { token=TokenContainer.end(); break; case TokenType::UNDEFINED: - TokenContainer.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Unrecognized character '"+token->sValue+"'.")); + ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Unrecognized character '"+token->sValue+"'.")); token++; break; - case TokenType::COMPILER_ERROR: - std::cout<sValue<<'\n'; - break; default: token++; break; } } if (bEOFFound==false) std::cout<<"warning: EOF not found!\n"; - return !bErrorsFound; + if (ErrorTokens.size()>=1) bErrorsFound=true; + return bErrorsFound; } } -// Convert menu TokenContainer into something useful. -void ParseMenuTokens(unsigned short& p_iBindCount) { +/* Convert menu TokenContainer into something useful. + * p_iBindCount (unsigned short) stores how many binds were counted + * p_bUsedDisplayFlags (a flag) stores what display types were used. + - 3rd bit: Is the "none" display method used? + - 2nd bit: Is the "console" display method used? + - 1st bit: Is the "captions" display method used? +*/ + +void ParseMenuTokens(unsigned short& p_iBindCount, unsigned char& p_bUsedDisplayFlags) { std::deque CMenuStack; std::stack NumKeyStack; // Variable is here to reduce the amount of goddamn downcasts I would have to do. @@ -162,6 +165,11 @@ void ParseMenuTokens(unsigned short& p_iBindCount) { { Parser::KVToken temp=static_cast(**token); KVMap.insert_or_assign(temp.Key,temp.Value); + + // Store what display types were used in p_bUsedDisplayFlags. + if (KVMap["display"]=="none") p_bUsedDisplayFlags |= 1; + else if (KVMap["display"]=="console") p_bUsedDisplayFlags |= 2; + else if (KVMap["display"]=="caption") p_bUsedDisplayFlags |= 4; } break; case Parser::CMenuTokenType::DECLARE_CMENU: diff --git a/src/compiler.hpp b/src/compiler.hpp index 47bc580..4a7be33 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -4,7 +4,7 @@ #include #include #include "token.hpp" -void ParseMenuTokens(unsigned short& p_iBindCount); +void ParseMenuTokens(unsigned short& p_iBindCount, unsigned char& p_bUsedDisplayFlags); namespace Parser { // For handling multi Tokens. enum CMenuTokenType {MENU_BIND=0, MENU_TOGGLE_BIND, DECLARE_CMENU, END_CMENU, KV_SET}; diff --git a/src/lex.cpp b/src/lex.cpp index d4c1f69..0815255 100644 --- a/src/lex.cpp +++ b/src/lex.cpp @@ -7,6 +7,7 @@ std::size_t iLineNum=1u; std::size_t iLineColumn=1u; +extern std::deque ErrorTokens; extern std::deque TokenContainer; extern std::deque CMenuTokens; @@ -52,161 +53,198 @@ namespace Lexer { { if (bInBlockComment) { if (p_sInStr.find("*/",i)==std::string::npos) { - TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::COMPILER_ERROR,std::to_string(iLineNum)+':'+std::to_string(iLineColumn)+": error: Block quote has no ending sequence ('*/').")); + ErrorTokens.push_back(Token(iLineNum,iLineColumn,TokenType::COMPILER_ERROR,std::to_string(iLineNum)+':'+std::to_string(iLineColumn)+": error: Block quote has no ending sequence ('*/').")); + bErrorsFound=true; + i=p_sInStr.length(); break; } else if (p_sInStr.at(i)=='*' && p_sInStr.at(i+1)=='/') { bInBlockComment=false; + i+=2; + iLineColumn+=2; + continue; } - } - if (TokenContainer.size()>0) TokenContainer.back().sValue.shrink_to_fit(); - // EOF Token - if (i == p_sInStr.length() - 1) { - TokenContainer.push_back(Token(iLineNum,p_sInStr.length()-1,TokenType::END_OF_FILE,"")); - TokenContainer.back().sValue.shrink_to_fit(); - break; - } - // Nonterminal - if (IsIdentChar(p_sInStr.at(i))) { - TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::IDENTIFIER,"")); - while (IsIdentChar(p_sInStr.at(i))) - { - TokenContainer.back().sValue.push_back(p_sInStr.at(i)); - i++; - iLineColumn++; + else switch (p_sInStr.at(i)) { + //spaces and colon + case '\t': + iLineColumn += 4 - (iLineColumn % 4); + i++; + break; + case ' ': + iLineColumn++; + i++; + break; + case '\r': + iLineColumn=1u; + if (i+1==p_sInStr.length() || p_sInStr.at(i+1)!='\n') iLineNum++; + i++; + break; + case '\v': + i++; + iLineNum++; + break; + case '\n': + iLineNum++; + if (i>0 && p_sInStr.at(i-1)!='\r') iLineColumn=1u; + i++; + break; + default: + i++; + iLineColumn++; + break; } - // Check for terminals. - if (TokenContainer.back().sValue=="TOGGLE") TokenContainer.back().Type=TokenType::TOGGLE; - else if (TokenContainer.back().sValue=="BIND") TokenContainer.back().Type=TokenType::BIND; - else if (TokenContainer.back().sValue=="NOEXIT") TokenContainer.back().Type=TokenType::NOEXIT; - else if (TokenContainer.back().sValue=="NOFORMAT") TokenContainer.back().Type=TokenType::NOFORMAT; - continue; } - switch (p_sInStr.at(i)) - { - // comments - case '/': - // Line comments - if (p_sInStr.at(i+1)=='/') { - for (auto t=p_sInStr.begin()+i; t!=p_sInStr.end(); t++, i++) { - if (*t=='\t') iLineColumn += 4 - (iLineColumn % 4); - else iLineColumn++; - if (*t=='\n' || *t=='\r') break; - } - } - /* Block comments */ - else if (p_sInStr.at(i+1)=='*') { // - bInBlockComment=true; - i+=2; - iLineColumn+=2; + else { + if (TokenContainer.size()>0) TokenContainer.back().sValue.shrink_to_fit(); + // EOF Token + if (i == p_sInStr.length() - 1) { + TokenContainer.push_back(Token(iLineNum,p_sInStr.length()-1,TokenType::END_OF_FILE,"")); + TokenContainer.back().sValue.shrink_to_fit(); + break; } - else { - TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::UNDEFINED,"/")); - iLineColumn++; - i++; + // Nonterminal + if (IsIdentChar(p_sInStr.at(i))) { + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::IDENTIFIER,"")); + while (IsIdentChar(p_sInStr.at(i))) + { + TokenContainer.back().sValue.push_back(p_sInStr.at(i)); + i++; + iLineColumn++; + } + // Check for terminals. + if (TokenContainer.back().sValue=="TOGGLE") TokenContainer.back().Type=TokenType::TOGGLE; + else if (TokenContainer.back().sValue=="BIND") TokenContainer.back().Type=TokenType::BIND; + else if (TokenContainer.back().sValue=="NOEXIT") TokenContainer.back().Type=TokenType::NOEXIT; + else if (TokenContainer.back().sValue=="NOFORMAT") TokenContainer.back().Type=TokenType::NOFORMAT; + continue; } - break; - // strings - case '\"': + switch (p_sInStr.at(i)) { - std::size_t tempcol=iLineColumn,templn=iLineNum; - // New lines or carriage returns cannot be in strings. (I don't mean the '\r' or '\n' character.) - for (i++, iLineColumn++; i < p_sInStr.length(); i++, iLineColumn++) { - if (p_sInStr.at(i)=='\r') { - TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::COMPILER_ERROR,std::to_string(iLineNum)+':'+std::to_string(iLineColumn)+": error: Ending '\"' is missing.")); - // - TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::STRING,"")); - t_sStrTemp=""; - iLineColumn=1u; - if (p_sInStr.at(i+1)!='\n') { - iLineNum++; - i++; + // comments + case '/': + // Line comments + if (p_sInStr.at(i+1)=='/') { + for (auto t=p_sInStr.begin()+i; t!=p_sInStr.end(); t++, i++) { + if (*t=='\t') iLineColumn += 4 - (iLineColumn % 4); + else iLineColumn++; + if (*t=='\n' || *t=='\r') break; } - break; } - else if (p_sInStr.at(i)=='\n') { - TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::COMPILER_ERROR,std::to_string(iLineNum)+':'+std::to_string(iLineColumn)+": error: Ending '\"' is missing.")); - // - TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::STRING,"")); - t_sStrTemp=""; - iLineNum++; - if (p_sInStr.at(i-1)!='\r') { - iLineColumn=1u; - i++; - } - break; + /* Block comments */ + else if (p_sInStr.at(i+1)=='*') { // + bInBlockComment=true; + i+=2; + iLineColumn+=2; } - else if (i==p_sInStr.length()-1){ - TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::COMPILER_ERROR,std::to_string(iLineNum)+':'+std::to_string(iLineColumn)+": error: Ending '\"' is missing.")); - t_sStrTemp=""; - break; + else { + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::UNDEFINED,"/")); + iLineColumn++; + i++; } - else if (p_sInStr.at(i)=='\"') { - TokenContainer.push_back(Token(tempcol,templn,TokenType::STRING,t_sStrTemp)); - t_sStrTemp=""; - break; + break; + // strings + case '\"': + { + std::size_t tempcol=iLineColumn,templn=iLineNum; + // New lines or carriage returns cannot be in strings. (I don't mean the '\r' or '\n' character.) + for (i++, iLineColumn++; i < p_sInStr.length(); i++, iLineColumn++) { + if (p_sInStr.at(i)=='\r') { + ErrorTokens.push_back(Token(iLineNum,iLineColumn,TokenType::COMPILER_ERROR,std::to_string(iLineNum)+':'+std::to_string(iLineColumn)+": error: Ending '\"' is missing.")); + bErrorsFound=true; + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::STRING,"")); + t_sStrTemp=""; + iLineColumn=1u; + if (p_sInStr.at(i+1)!='\n') { + iLineNum++; + i++; + } + break; + } + else if (p_sInStr.at(i)=='\n') { + ErrorTokens.push_back(Token(iLineNum,iLineColumn,TokenType::COMPILER_ERROR,std::to_string(iLineNum)+':'+std::to_string(iLineColumn)+": error: Ending '\"' is missing.")); + bErrorsFound=true; + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::STRING,"")); + t_sStrTemp=""; + iLineNum++; + if (p_sInStr.at(i-1)!='\r') { + iLineColumn=1u; + i++; + } + break; + } + else if (i==p_sInStr.length()-1){ + ErrorTokens.push_back(Token(iLineNum,iLineColumn,TokenType::COMPILER_ERROR,std::to_string(iLineNum)+':'+std::to_string(iLineColumn)+": error: Ending '\"' is missing.")); + bErrorsFound=true; + t_sStrTemp=""; + break; + } + else if (p_sInStr.at(i)=='\"') { + TokenContainer.push_back(Token(tempcol,templn,TokenType::STRING,t_sStrTemp)); + t_sStrTemp=""; + break; + } + else { + if (p_sInStr.at(i)=='\t') iLineColumn += 4 - (iLineColumn % 4); + t_sStrTemp+=p_sInStr.at(i); + } } - else { - if (p_sInStr.at(i)=='\t') iLineColumn += 4 - (iLineColumn % 4); - t_sStrTemp+=p_sInStr.at(i); + i++; // Starts at the ending quote if this doesn't exist. + iLineColumn++; } + break; + //terminals + case '=': + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::EQUALS,"=")); + i++; + iLineColumn++; + break; + case '|': + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::VBAR,"|")); + i++; + iLineColumn++; + break; + case '{': + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::LCBRACKET,"{")); + i++; + iLineColumn++; + break; + case '}': + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::RCBRACKET,"}")); + i++; + iLineColumn++; + break; + //spaces and colon + case '\t': + iLineColumn += 4 - (iLineColumn % 4); + i++; + break; + case ' ': + iLineColumn++; + i++; + break; + case '\r': + iLineColumn=1u; + if (i+1==p_sInStr.length() || p_sInStr.at(i+1)!='\n') iLineNum++; + i++; + break; + case '\v': + i++; + iLineNum++; + break; + case '\n': + iLineNum++; + if (i>0 && p_sInStr.at(i-1)!='\r') iLineColumn=1u; + i++; + break; + default: + ErrorTokens.push_back(Token(iLineNum,iLineColumn,TokenType::UNDEFINED,"")); + ErrorTokens.back().sValue.push_back(p_sInStr.at(i)); + iLineColumn++; + i++; + break; } - i++; // Starts at the ending quote if this doesn't exist. - iLineColumn++; - } - break; - //terminals - case '=': - TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::EQUALS,"=")); - i++; - iLineColumn++; - break; - case '|': - TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::VBAR,"|")); - i++; - iLineColumn++; - break; - case '{': - TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::LCBRACKET,"{")); - i++; - iLineColumn++; - break; - case '}': - TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::RCBRACKET,"}")); - i++; - iLineColumn++; - break; - //spaces and colon - case '\t': - iLineColumn += 4 - (iLineColumn % 4); - i++; - break; - case ' ': - iLineColumn++; - i++; - break; - case '\r': - iLineColumn=1u; - if (i+1==p_sInStr.length() || p_sInStr.at(i+1)!='\n') iLineNum++; - i++; - break; - case '\v': - i++; - iLineNum++; - break; - case '\n': - iLineNum++; - if (i>0 && p_sInStr.at(i-1)!='\r') iLineColumn=1u; - i++; - break; - default: - TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::UNDEFINED,"")); - TokenContainer.back().sValue.push_back(p_sInStr.at(i)); - iLineColumn++; - i++; - break; } } - return !bErrorsFound; + return bErrorsFound; } } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 19a69fa..f485749 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,7 +20,7 @@ std::map KVMap={ {"linger_time","0"}, {"predisplay_time","0.25"}, {"format","$(nkey). $(str)"}, - {"consolemode","false"}, + {"display","caption"}, {"resetkeys","bind 1 slot1; bind 2 slot2; bind 3 slot3; bind 4 slot4; bind 5 slot5; bind 6 slot6; bind 7 slot7; bind 8 slot8; bind 9 slot9; bind 0 slot10"} }; std::wstring_convert,wchar_t> convert; @@ -28,68 +28,54 @@ std::wstring_convert,wchar_t> convert; extern std::filesystem::path InputFilePath; extern std::filesystem::path sOutputDir; int main(int argc, char** argv) { - unsigned short iBindCount=0u; + // Evaluate launch options. if (!EvaluateLaunchOptions(argc,argv)) return -1; + // Get content from input file. std::string Line, InFileContent; std::ifstream inputf(InputFilePath,std::ios_base::binary); while (std::getline(inputf,Line)) { InFileContent+=Line+'\n'; } - // If tokenization and parsing process failed, then error out and return. - if (!Lexer::Tokenize(InFileContent) - || !Parser::ParseTokens()) { + // If tokenization and parsing process failed then error out and return. + if (Lexer::Tokenize(InFileContent) + || Parser::ParseTokens()) { + + for (auto& e : ErrorTokens) { + std::cout << e.sValue << '\n'; + } return -1; } - // Use the parsed tokens to form CMenus. - ParseMenuTokens(iBindCount); - // Directories - std::filesystem::create_directories(sOutputDir.string()+"/cfg/cmenu"); - // Main CFG file that initializes our CMenus. - std::ofstream InitRoutineFile(sOutputDir.string()+"/cfg/cmenu_initialize.cfg"); - // Console mode makes the Voicemenu use the console for displaying binds, instead of captions. - bool bConsoleModeTrue=(KVMap["bConsoleModeTrue"].find("true")!=std::string::npos); - if (bConsoleModeTrue) { - InitRoutineFile<sRawName+".cfg"; - std::ofstream CMenuCFG(CMenuCFGPath); - // Write to cfg - CMenuCFG<<"_cmenu.menusettings\n_cvm.nullkeys\n"; - for (auto& kbind : CMenu->binds) { - if (kbind.bToggleBind) { - InitRoutineFile<<"alias _cmenu.toggle_"<sRawName+".cfg"; std::ofstream CMenuCFG(CMenuCFGPath); + /* Disable other displays if this CMenu isnt using it and there are other CMenus that use it.*/ + + if (CMenu->Display!=CMenuDisplayType::CONSOLE && (bUsedDisplayFlags & 2)) + CMenuCFG<<"developer 0\n"; + if (CMenu->Display!=CMenuDisplayType::CAPTIONS && (bUsedDisplayFlags & 4)) + CMenuCFG<<"cc_emit _#cmenu.clear_screen\n"; + /* Create the actual binds needed for the declared binds. */ - CMenuCFG<<"_cmenu.menusettings\ncc_emit _#cmenu.clear_screen\ncc_emit _#cmenu."+CMenu->sRawName+'\n'; + if (CMenu->Display==CMenuDisplayType::CAPTIONS) CMenuCFG<<"cc_linger_time 10000\ncc_predisplay_time 0\ncc_emit _#cmenu.clear_screen\ncc_emit _#cmenu."+CMenu->sRawName+'\n'; + else if (CMenu->Display==CMenuDisplayType::CONSOLE) CMenuCFG<<"developer 1\nclear\n"; + CMenuCFG<<"bind 1 _cmenu.1\nbind 2 _cmenu.2\nbind 3 _cmenu.3\nbind 4 _cmenu.4\nbind 5 _cmenu.5\nbind 6 _cmenu.6\nbind 7 _cmenu.7\nbind 8 _cmenu.8\nbind 9 _cmenu.9\nbind 0 _cmenu.0\n"; { unsigned int t_ToggleNum=iToggleNumber; - for (auto kbind=CMenu->binds.begin(); kbind!=CMenu->binds.end(); kbind++) { - if (kbind->bToggleBind==true) { + for (auto kTBind=CMenu->binds.begin(); kTBind!=CMenu->binds.end(); kTBind++) { + if (CMenu->Display != CMenuDisplayType::NONE && kTBind->bToggleBind==true) { CMenuCFG<<"_#cmenu.toggle_"+std::to_string(t_ToggleNum)<<'\n'; t_ToggleNum++; } - if (kbind!=CMenu->binds.begin() && kbind->bToggleBind==false && (kbind-1)->bToggleBind==true) { + if (CMenu->Display == CMenuDisplayType::CAPTIONS && kTBind!=CMenu->binds.begin() && kTBind->bToggleBind==false && (kTBind-1)->bToggleBind==true) { CMenuCFG<<"cc_emit _#cmenu."<sRawName<<"_seg_"<binds.begin(); kbind!=CMenu->binds.end(); kbind++) { - if (kbind==CMenu->binds.begin() && kbind->bToggleBind!=true) - CMenuCaptionFile<sRawName+"\" \""); - if (kbind->bToggleBind==true) { - InitRoutineFile<<"alias _cmenu.toggle_"<NameContainer.size(); sti++) { - InitRoutineFile<<"alias _cmenu.toggle_"<NameContainer.size())<<';'<CmdStrContainer.at(sti)<<"; alias _cmenu.toggle_"<NameContainer.size())<<"\"\n"; - InitRoutineFile<<"alias _#cmenu.toggle_"<NameContainer.at(sti)+"\"\n"); + for (auto kBind = CMenu->binds.begin(); kBind != CMenu->binds.end(); kBind++) { + if (CMenu->Display==CMenuDisplayType::CAPTIONS) { + if (kBind==CMenu->binds.begin() && kBind->bToggleBind!=true) + CMenuCaptionFile<sRawName+"\" \""); + if (kBind->bToggleBind==true) { + InitRoutineFile<<"alias _cmenu.toggle_"<NameContainer.size(); sti++) { + InitRoutineFile<<"alias _cmenu.toggle_"<NameContainer.size())<<';'<CmdStrContainer.at(sti)<<"; alias _cmenu.toggle_"<NameContainer.size())<<"\"\n"; + InitRoutineFile<<"alias _#cmenu.toggle_"<NameContainer.at(sti)+"\"\n"); + } + CMenuCFG<<"alias _cmenu."<cKey)<<"\"_cmenu.toggle_"<binds.begin() && (kBind-1)->bToggleBind==true) { + CMenuCaptionFile<sRawName+"_seg_"+std::to_string(iTBindSegmentNum)+"\" \""); + iTBindSegmentNum++; + } + CMenuCaptionFile<NameContainer.front()); + if (kBind==CMenu->binds.end()-1 || (kBind+1)->bToggleBind==true) CMenuCaptionFile<cKey)<<"\""<CmdStrContainer.at(0)<<"\"\n"; } - CMenuCFG<<"alias _cmenu."<cKey)<<" \"_cmenu.toggle_"<binds.begin() && (kbind-1)->bToggleBind==true) { - CMenuCaptionFile<sRawName+"_seg_"+std::to_string(iTBindSegmentNum)+"\" \""); - iTBindSegmentNum++; + else if (CMenu->Display==CMenuDisplayType::CONSOLE) { + if (kBind->bToggleBind) { + InitRoutineFile<<"alias _cmenu.toggle_"<NameContainer.size(); sti++) { + InitRoutineFile<<"alias _cmenu.toggle_"<CmdStrContainer.at(sti)<<"; alias _cmenu.toggle_"<NameContainer.size())<<"; alias _#cmenu.toggle_"<NameContainer.size())<<"\"\n"; + InitRoutineFile<<"alias _#cmenu.toggle_"<NameContainer.at(sti)<<"\"\n"; + } + CMenuCFG<<"_#cmenu.toggle_"<cKey)<<" \"_cmenu.toggle_"<NameContainer.front()<<'\n'<<"alias _cmenu."<cKey)<<" \""<CmdStrContainer.front()<<"\"\n";; + } + } + else if (CMenu->Display==CMenuDisplayType::NONE) { + if (kBind->bToggleBind) { + InitRoutineFile<<"alias _cmenu.toggle_"<NameContainer.size(); sti++) { + InitRoutineFile<<"alias _cmenu.toggle_"<CmdStrContainer.at(sti)<<"; alias _cmenu.toggle_"<NameContainer.size())<<"\n"; + } + CMenuCFG<<"alias _cmenu."<cKey)<<" \"_cmenu.toggle_"<cKey)<<" \""<CmdStrContainer.front()<<"\"\n";; } - CMenuCaptionFile<NameContainer.front()); - if (kbind==CMenu->binds.end()-1 || (kbind+1)->bToggleBind==true) CMenuCaptionFile<cKey)<<" \""<CmdStrContainer.at(0)<<"\"\n"; } } } + // We're done compiling so close the file streams. CMenuCaptionFile<<"\t}\n}"; CMenuCaptionFile.close(); - } InitRoutineFile<<"\necho [Command Menu Generator] Initialized command menus!"; InitRoutineFile.close(); //Done! diff --git a/src/token.hpp b/src/token.hpp index e3de202..fe781dc 100644 --- a/src/token.hpp +++ b/src/token.hpp @@ -21,7 +21,7 @@ class Token { unsigned char Type=TokenType::UNDEFINED; std::size_t iLineColumn=1u; // Location std::size_t iLineNum=1u; // Location from newline - std::string sValue; + std::string sValue=""; Token(); Token(const std::size_t& p_iLineNum, const std::size_t& p_iColumn, const unsigned char p_TokenType, const std::string& p_sVal); From f6c3e3445f55edd7a86aaa421ccdcd800ddfcadf Mon Sep 17 00:00:00 2001 From: WhyIsEvery4thYearAlwaysBad Date: Sun, 11 Apr 2021 00:41:05 -0500 Subject: [PATCH 04/11] Toggle Binds should now properly reset NOFORMAT modifier. --- src/compiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index 59c055f..68aa7d1 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -54,7 +54,7 @@ namespace Parser { if ((token+i)->Type!=TokenType::VBAR) ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+"error: Expected '|'.")); if (!bErrorsFound) CMenuTokens.push_back(new Parser::ToggleBindToken(NameList,CmdList,static_cast((i-2)/2),bNoExit,bFormatted)); - if (bNoExit==true) bNoExit=false; + bNoExit=false, bFormatted=true; token+=i; } break; From e59c096aa7a2cede63253ec70b2e85582f48e755 Mon Sep 17 00:00:00 2001 From: WhyIsEvery4thYearAlwaysBad Date: Sun, 11 Apr 2021 00:43:37 -0500 Subject: [PATCH 05/11] CMenus with NOEXIT modifiers arent always meant to be binds. --- src/compiler.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index 68aa7d1..bd725f8 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -82,12 +82,12 @@ namespace Parser { case TokenType::STRING: // Check for new commandmenu. { unsigned short i=1u; + if (bNoExit==true) { + ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: 'NOEXIT' modifier cannot be used with CMenus.")); + bNoExit = false; + } if ((token+i)->Type!=TokenType::LCBRACKET) ErrorTokens.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected '{' here.")); - else if (bNoExit==true) { - ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Expected a bind.")); - bNoExit=false; - } if (!bErrorsFound) CMenuTokens.push_back(new Parser::CMenuToken(token->sValue,bFormatted)); bFormatted=true; token+=i; From 543973bc5e2addca07dc4362f9a6ed89da5f614f Mon Sep 17 00:00:00 2001 From: WhyIsEvery4thYearAlwaysBad Date: Sun, 11 Apr 2021 00:44:28 -0500 Subject: [PATCH 06/11] Fixed: Incorrectly verifying the amount of left and right curly braces are even. --- src/compiler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index bd725f8..9baec58 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -91,7 +91,6 @@ namespace Parser { if (!bErrorsFound) CMenuTokens.push_back(new Parser::CMenuToken(token->sValue,bFormatted)); bFormatted=true; token+=i; - depth++; } break; case TokenType::IDENTIFIER: // Check for set keymaps From be344b8385379be73074c10bcdc2ea55aeba880f Mon Sep 17 00:00:00 2001 From: WhyIsEvery4thYearAlwaysBad Date: Sun, 11 Apr 2021 00:50:55 -0500 Subject: [PATCH 07/11] Made depth/iCMenuDepth var signed to reduce theoretical false positives. --- src/compiler.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index 9baec58..e9e0f0f 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -17,7 +17,7 @@ extern std::deque CMenuContainer; // Made in main.cpp namespace Parser { - unsigned int depth=0u; + int iCMenuDepth=0; // Records how nested is a CMenu. bool bEOFFound=false, bErrorsFound=false; bool ParseTokens() { bool bNoExit=false, bFormatted=true; @@ -38,7 +38,7 @@ namespace Parser { std::string NameList[MAX_TOGGLE_STATES]; std::string CmdList[MAX_TOGGLE_STATES]; unsigned short i=1; - if (depth<=0) + if (iCMenuDepth<=0) ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Toggle bind must be set in a command menu.")); if ((token+i)->Type!=TokenType::BIND) ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Expected \'BIND\' keyword here.")); @@ -61,7 +61,7 @@ namespace Parser { case TokenType::BIND: // Check for bind. { unsigned short i=1u; - if (depth<=0) + if (iCMenuDepth<=0) ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Bind must be set in a command menu.")); if ((token+i)->Type!=TokenType::STRING) ErrorTokens.push_back(Token((token+i)->iLineNum,(token+i)->iLineColumn,TokenType::COMPILER_ERROR,(token+i)->GetFileLoc()+": error: Expected a string.")); @@ -109,18 +109,18 @@ namespace Parser { } break; case TokenType::LCBRACKET: - depth++; + iCMenuDepth++; if (token>TokenContainer.begin() && (token-1)->Type!=TokenType::STRING) { ErrorTokens.push_back(Token((token-1)->iLineNum,(token-1)->iLineColumn,TokenType::COMPILER_ERROR,(token-1)->GetFileLoc()+": error: Expected a string here.")); - depth--; + iCMenuDepth--; } token++; break; case TokenType::RCBRACKET: - depth--; - if (depth==UINT32_MAX) { + iCMenuDepth--; + if (iCMenuDepth<0) { ErrorTokens.push_back(Token(token->iLineNum,token->iLineColumn,TokenType::COMPILER_ERROR,token->GetFileLoc()+": error: Stray '}'")); - depth++; + iCMenuDepth++; } if (!bErrorsFound) CMenuTokens.push_back(new Parser::CMenuEndToken()); token++; From 58caf7b49184394648719d3d6e0473916358a433 Mon Sep 17 00:00:00 2001 From: WhyIsEvery4thYearAlwaysBad Date: Sun, 11 Apr 2021 00:57:27 -0500 Subject: [PATCH 08/11] ParseMenuTokens() has safeguards against invalid accesses. This function will error out and end the program if invalid accesses to containers are made. --- src/compiler.cpp | 59 ++++++++++++++++++++++++++++++++++++------------ src/compiler.hpp | 2 +- src/main.cpp | 12 +++++----- 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index e9e0f0f..ad9e57a 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -152,7 +152,7 @@ namespace Parser { - 1st bit: Is the "captions" display method used? */ -void ParseMenuTokens(unsigned short& p_iBindCount, unsigned char& p_bUsedDisplayFlags) { +bool ParseMenuTokens(unsigned short& p_iBindCount, unsigned char& p_bUsedDisplayFlags) { std::deque CMenuStack; std::stack NumKeyStack; // Variable is here to reduce the amount of goddamn downcasts I would have to do. @@ -196,27 +196,56 @@ void ParseMenuTokens(unsigned short& p_iBindCount, unsigned char& p_bUsedDisplay } break; case Parser::CMenuTokenType::END_CMENU: - // Warning: - if (CMenuStack.front().binds.size()>10) std::cout<<"Warning: More than ten binds in CMenu \'"< 0) { + // Warning: + if (CMenuStack.front().binds.size()>10) std::cout<<"Warning: More than ten binds in CMenu \'"<(**token))); - NumKeyStack.top()=(NumKeyStack.top()+1)%10; - p_iBindCount++; + if (CMenuStack.size() > 0) { + CMenuStack.front().binds.push_back(Bind(NumKeyStack.top(),static_cast(**token))); + NumKeyStack.top()=(NumKeyStack.top()+1)%10; + p_iBindCount++; + } + else { + std::cerr<<"ParseMenuTokens():CMenuTokens+"<(**token))); - NumKeyStack.top()=(NumKeyStack.top()+1)%10; - p_iBindCount++; - break; + if (CMenuStack.size() > 0) { + CMenuStack.front().binds.push_back(Bind(NumKeyStack.top(),static_cast(**token))); + if (!NumKeyStack.empty()) { + NumKeyStack.top()=(NumKeyStack.top()+1)%10; + } + else { + std::cerr<<"ParseMenuTokens():CMenuTokens+"< #include #include "token.hpp" -void ParseMenuTokens(unsigned short& p_iBindCount, unsigned char& p_bUsedDisplayFlags); +bool ParseMenuTokens(unsigned short& p_iBindCount, unsigned char& p_bUsedDisplayFlags); namespace Parser { // For handling multi Tokens. enum CMenuTokenType {MENU_BIND=0, MENU_TOGGLE_BIND, DECLARE_CMENU, END_CMENU, KV_SET}; diff --git a/src/main.cpp b/src/main.cpp index f485749..1fa305b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,19 +36,19 @@ int main(int argc, char** argv) { while (std::getline(inputf,Line)) { InFileContent+=Line+'\n'; } - // If tokenization and parsing process failed then error out and return. + // If tokenization and parsing process failed then error out and return. Also get the compiled bind count. + unsigned short iBindCount=0u; + unsigned char bUsedDisplayFlags=0; // Flag used to mark if and what display types were used. if (Lexer::Tokenize(InFileContent) - || Parser::ParseTokens()) { + || Parser::ParseTokens() + || ParseMenuTokens(iBindCount,bUsedDisplayFlags)) { for (auto& e : ErrorTokens) { std::cout << e.sValue << '\n'; } return -1; } - // Use the parsed tokens to form CMenus. Also get the compiled bind count. - unsigned short iBindCount=0u; - unsigned char bUsedDisplayFlags=0; // Flag used to mark if and what display types were used. - ParseMenuTokens(iBindCount,bUsedDisplayFlags); + /* display="caption" - Makes cmenus use the caption for bind displays display="console" - Makes cmenus use the console for bind displys From 406cc59d59d72ff91db099785be434bcca6b7952 Mon Sep 17 00:00:00 2001 From: WhyIsEvery4thYearAlwaysBad Date: Sun, 11 Apr 2021 00:59:55 -0500 Subject: [PATCH 09/11] String line coordinates should be stored properly again. --- src/lex.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lex.cpp b/src/lex.cpp index 0815255..e2ec646 100644 --- a/src/lex.cpp +++ b/src/lex.cpp @@ -145,7 +145,6 @@ namespace Lexer { // strings case '\"': { - std::size_t tempcol=iLineColumn,templn=iLineNum; // New lines or carriage returns cannot be in strings. (I don't mean the '\r' or '\n' character.) for (i++, iLineColumn++; i < p_sInStr.length(); i++, iLineColumn++) { if (p_sInStr.at(i)=='\r') { @@ -179,7 +178,7 @@ namespace Lexer { break; } else if (p_sInStr.at(i)=='\"') { - TokenContainer.push_back(Token(tempcol,templn,TokenType::STRING,t_sStrTemp)); + TokenContainer.push_back(Token(iLineNum,iLineColumn,TokenType::STRING,t_sStrTemp)); t_sStrTemp=""; break; } From 593c154c2d36b39206f76492bcdd3f88f589013c Mon Sep 17 00:00:00 2001 From: WhyIsEvery4thYearAlwaysBad Date: Sun, 11 Apr 2021 01:03:25 -0500 Subject: [PATCH 10/11] Carriage return should properly increase line number again. --- src/lex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lex.cpp b/src/lex.cpp index e2ec646..36128f0 100644 --- a/src/lex.cpp +++ b/src/lex.cpp @@ -76,7 +76,7 @@ namespace Lexer { break; case '\r': iLineColumn=1u; - if (i+1==p_sInStr.length() || p_sInStr.at(i+1)!='\n') iLineNum++; + if ((i+1) Date: Sun, 11 Apr 2021 01:03:31 -0500 Subject: [PATCH 11/11] Formatting. --- src/compiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index ad9e57a..c9c0228 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -78,7 +78,7 @@ namespace Parser { bNoExit=false, bFormatted=true; token+=i; } - break; + break; case TokenType::STRING: // Check for new commandmenu. { unsigned short i=1u;