diff options
| Commit | 26e5f891d537b5d4fc2890c9cdbeb73d5748d568 (patch) | |
|---|---|---|
| Author | 2018-11-03 13:34:18 +0200 | |
| Committer | 2018-11-03 13:34:18 +0200 | |
| Files | 702aa5c2110f0fb7afccebe3bf894747a70e94c0 | |
| IPL-26e5f891d537b5d4fc2890c9cdbeb73d5748d568.tar IPL-26e5f891d537b5d4fc2890c9cdbeb73d5748d568.tar.gz IPL-26e5f891d537b5d4fc2890c9cdbeb73d5748d568.zip | ||
| Parent | 0b0962d77111cacc8c1f1a265eb1211e7d44fea4 (diff) | |
homework 1 (#27)
5 files changed, 1065 insertions, 0 deletions
| -rw-r--r-- | homework/81625/cpp2html/.gitignore | 5 | ||||
| -rw-r--r-- | homework/81625/cpp2html/cpp2.html | 41 | ||||
| -rw-r--r-- | homework/81625/cpp2html/src/Lexer.cpp | 689 | ||||
| -rw-r--r-- | homework/81625/cpp2html/src/Lexer.h | 223 | ||||
| -rw-r--r-- | homework/81625/cpp2html/src/main.cpp | 107 |
diff --git a/homework/81625/cpp2html/.gitignore b/homework/81625/cpp2html/.gitignore new file mode 100644 index 0000000..c53f09b --- /dev/null +++ b/homework/81625/cpp2html/.gitignore @@ -0,0 +1,5 @@ +cpp2html +Lexer.h~ +Lexer.cpp~ +main.cpp~ +.gitignore~ diff --git a/homework/81625/cpp2html/cpp2.html b/homework/81625/cpp2html/cpp2.html new file mode 100644 index 0000000..3c37e5e --- /dev/null +++ b/homework/81625/cpp2html/cpp2.html @@ -0,0 +1,41 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <style> + body { + font-size: 20px; + } + + .number { + color: pink; + } + + .string { + color: blue; + } + + .keyword { + color: purple; + font-weight: bold; + } + + .operator { + color: red; + } + + .comment { + color: gray; + font-style: italic; + } + + .preprocessor { + color: green; + font-weight: bold; + } + + </style> +</head> +<body> +<span class="preprocessor">#include</span><span class="operator"><</span>iostream<span class="operator">></span><br><span class="keyword">bool</span> isCapitalCase<span class="operator">(</span><span class="keyword">char</span> c<span class="operator">)</span><br><span class="operator">{</span><br>    <span class="keyword">return</span> c <span class="operator">>=</span> <span class="string">'A'</span> <span class="operator">&&</span> c <span class="operator"><=</span> <span class="string">'Z'</span><span class="operator">;</span><br><span class="operator">}</span><br>m_KeyWordsTable<span class="operator">[</span><span class="string">"break"</span><span class="operator">]</span> <span class="operator">=</span> TokenType<span class="operator">::</span>Break<span class="operator">;</span><br><span class="comment">// this is a comment test</span><br><span class="comment">/* another one */</span> +</body> +</html>
\ No newline at end of file diff --git a/homework/81625/cpp2html/src/Lexer.cpp b/homework/81625/cpp2html/src/Lexer.cpp new file mode 100644 index 0000000..63d208b --- /dev/null +++ b/homework/81625/cpp2html/src/Lexer.cpp @@ -0,0 +1,689 @@ +#include "Lexer.h" + +bool isDigit(char c) +{ + return c >= '0' && c <= '9'; +} + +bool isLowerCase(char c) +{ + return c >= 'a' && c <= 'z'; +} + +bool isCapitalCase(char c) +{ + return c >= 'A' && c <= 'Z'; +} + + +Tokenizer::Tokenizer(const char* code) : + line(1), column(0), codeIndex(0), code(code), state(State::SUCCESS) +{ + keywords["alignas"] = TokenType::ALIGNAS; + keywords["alignof"] = TokenType::ALIGNOF; + keywords["and"] = TokenType::AND; + keywords["and_eq"] = TokenType::AND_EQ; + keywords["asm"] = TokenType::ASM; + keywords["auto"] = TokenType::AUTO; + keywords["bitand"] = TokenType::BITAND; + keywords["bitor"] = TokenType::BITOR; + keywords["bool"] = TokenType::BOOL; + keywords["break"] = TokenType::BREAK; + keywords["case"] = TokenType::CASE; + keywords["catch"] = TokenType::CATCH; + keywords["char"] = TokenType::CHAR; + keywords["char16_t"] = TokenType::CHAR16_T; + keywords["char32_t"] = TokenType::CHAR32_T; + keywords["class"] = TokenType::CLASS; + keywords["compl"] = TokenType::COMPL; + keywords["const"] = TokenType::CONST; + keywords["constexpr"] = TokenType::CONSTEXPR; + keywords["const_cast"] = TokenType::CONST_CAST; + keywords["continue"] = TokenType::CONTINUE; + keywords["decltype"] = TokenType::DECLTYPE; + keywords["default"] = TokenType::DEFAULT; + keywords["delete"] = TokenType::DELETE; + keywords["do"] = TokenType::DO; + keywords["double"] = TokenType::DOUBLE; + keywords["dynamic_cast"] = TokenType::DYNAMIC_CAST; + keywords["else"] = TokenType::ELSE; + keywords["enum"] = TokenType::ENUM; + keywords["explicit"] = TokenType::EXPLICIT; + keywords["export"] = TokenType::EXPORT; + keywords["extern"] = TokenType::EXTERN; + keywords["false"] = TokenType::FALSE; + keywords["float"] = TokenType::FLOAT; + keywords["for"] = TokenType::FOR; + keywords["friend"] = TokenType::FRIEND; + keywords["goto"] = TokenType::GOTO; + keywords["if"] = TokenType::IF; + keywords["inline"] = TokenType::INLINE; + keywords["int"] = TokenType::INT; + keywords["long"] = TokenType::LONG; + keywords["mutable"] = TokenType::MUTABLE; + keywords["namespace"] = TokenType::NAMESPACE; + keywords["new"] = TokenType::NEW; + keywords["noexcept"] = TokenType::NOEXCEPT; + keywords["not"] = TokenType::NOT; + keywords["not_eq"] = TokenType::NOT_EQ; + keywords["nullptr"] = TokenType::NULLPTR; + keywords["operator"] = TokenType::OPERATOR; + keywords["or"] = TokenType::OR; + keywords["or_eq"] = TokenType::OR_EQ; + keywords["private"] = TokenType::PRIVATE; + keywords["protected"] = TokenType::PROTECTED; + keywords["public"] = TokenType::PUBLIC; + keywords["register"] = TokenType::REGISTER; + keywords["reinterpret_cast"]= TokenType::REINTERPRET_CAST; + keywords["return"] = TokenType::RETURN; + keywords["short"] = TokenType::SHORT; + keywords["signed"] = TokenType::SIGNED; + keywords["sizeof"] = TokenType::SIZEOF; + keywords["static"] = TokenType::STATIC; + keywords["static_assert"] = TokenType::STATIC_ASSERT; + keywords["static_cast"] = TokenType::STATIC_CAST; + keywords["struct"] = TokenType::STRUCT; + keywords["switch"] = TokenType::SWITCH; + keywords["template"] = TokenType::TEMPLATE; + keywords["this"] = TokenType::THIS; + keywords["thread_local"] = TokenType::THREAD_LOCAL; + keywords["throw"] = TokenType::THROW; + keywords["true"] = TokenType::TRUE; + keywords["try"] = TokenType::TRY; + keywords["typedef"] = TokenType::TYPEDEF; + keywords["typeid"] = TokenType::TYPEID; + keywords["typename"] = TokenType::TYPENAME; + keywords["union"] = TokenType::UNION; + keywords["unsigned"] = TokenType::UNSIGNED; + keywords["using"] = TokenType::USING; + keywords["virtual"] = TokenType::VIRTUAL; + keywords["void"] = TokenType::VOID; + keywords["volatile"] = TokenType::VOLATILE; + keywords["wchar_t"] = TokenType::WCHAR_T; + keywords["while"] = TokenType::WHILE; + keywords["xor"] = TokenType::XOR; + keywords["xor_eq"] = TokenType::XOR_EQ; + + preprocessors["#define"] = TokenType::PRE_DEFINE; + preprocessors["#undef"] = TokenType::PRE_UNDEF; + preprocessors["#include"] = TokenType::PRE_INCLUDE; + preprocessors["#if"] = TokenType::PRE_IF; + preprocessors["#ifdef"] = TokenType::PRE_IFDEF; + preprocessors["#ifndef"] = TokenType::PRE_IFNDEF; + preprocessors["#else"] = TokenType::PRE_ELSE; + preprocessors["#elif"] = TokenType::PRE_ELIF; + preprocessors["#endif"] = TokenType::PRE_ENDIF; + preprocessors["#line"] = TokenType::PRE_LINE; + preprocessors["#error"] = TokenType::PRE_ERROR; + preprocessors["#pragma"] = TokenType::PRE_PRAGMA; +} + +bool Tokenizer::isAtEOF() const +{ + return code[codeIndex] == '\0'; +} + +bool Tokenizer::match(char c) const +{ + return code[codeIndex] == c; +} + +bool Tokenizer::isStateError() const +{ + return state == State::ERROR; +} + +bool Tokenizer::isStateSuccess() const +{ + return state == State::SUCCESS; +} + +bool Tokenizer::tokenize(std::vector<Token> &tokens) +{ + Token token; + do + { + token = nextToken(); + if(token.type == TokenType::INVALID) + { + return false; + } + tokens.push_back(token); + + } while(token.type != TokenType::Eof); + + return true; +} + +void Tokenizer::skipWhiteSpaces() +{ + while(true) + { + if(code[codeIndex] == ' ' || code[codeIndex] == '\t') + { + column++; + } + else if(code[codeIndex] == '\n') + { + column = 0; + line++; + } + else + { + break; + } + codeIndex++; + } +} + +void Tokenizer::nextSymbol() +{ + codeIndex++; + column++; +} + +void Tokenizer::prevSymbol() +{ + codeIndex--; + column--; +} + +double Tokenizer::parseNumber() +{ + try + { + size_t bytes = 0; + double d = std::stod(code + codeIndex, &bytes); + codeIndex += static_cast<unsigned>(bytes); + column += static_cast<unsigned>(bytes); + state = State::SUCCESS; + return d; + } + catch(std::invalid_argument &e) + { + state = State::FAIL; + return 0; + } + catch(std::out_of_range &e) + { + state = State::ERROR; + return 0; + } +} + +std::string Tokenizer::parseComment() +{ + if(code[codeIndex] == '/') + { + unsigned start = codeIndex; + nextSymbol(); + if(code[codeIndex] == '/') + { + nextSymbol(); + while(code[codeIndex] != '\n') + { + nextSymbol(); + } + state = State::SUCCESS; + return std::string(code, start, codeIndex-start); + } + if(code[codeIndex] == '*') + { + nextSymbol(); + bool flag = true; + while(flag) + { + while(code[codeIndex] != '*' && !isAtEOF()) + { + nextSymbol(); + } + + if(isAtEOF()) + { + state = State::ERROR; + return ""; + } + + nextSymbol(); + if(code[codeIndex] == '/') + { + nextSymbol(); + flag = false; + } + } + state = State::SUCCESS; + return std::string(code, start, codeIndex-start); + } + } + + state = State::FAIL; + return ""; +} + +std::string Tokenizer::parseString() +{ + // not a string + if(code[codeIndex] != '\'' && code[codeIndex] != '"' ) + { + state = State::FAIL; + return ""; + } + + const char bound = code[codeIndex]; + const unsigned start = codeIndex; + + nextSymbol(); + while(true) + { + while(code[codeIndex] != bound && !isAtEOF() && code[codeIndex] != '\n') + { + nextSymbol(); + } + + if(code[codeIndex] == bound) + { + // escaping character + if(code[codeIndex-1] != '\\') + { + nextSymbol(); + state = State::SUCCESS; + return std::string(code, start, codeIndex-start); + } + else + { + codeIndex++; + } + } + else break; + } + + // not a correct string + state = State::ERROR; + return ""; +} + +Token Tokenizer::parseKeyword() +{ + if(!isLowerCase(code[codeIndex])) + { + state = State::FAIL; + return produceToken(TokenType::INVALID); + } + + const unsigned start = codeIndex; + nextSymbol(); + while(isLowerCase(code[codeIndex]) || isDigit(code[codeIndex]) || code[codeIndex] == '_') + { + nextSymbol(); + } + + const std::string key = std::string(code, start, codeIndex-start); + const auto keyword = keywords.find(key); + + if(keyword == keywords.end()) + { + column -= codeIndex-start; + codeIndex = start; + state = State::FAIL; + return produceToken(TokenType::INVALID); + } + + state = State::SUCCESS; + return produceToken(keyword->second, keyword->first); +} + +Token Tokenizer::parsePreprocessor() +{ + // not a preprocessor + if(code[codeIndex] != '#') + { + state = State::FAIL; + return produceToken(TokenType::INVALID); + } + + const unsigned start = codeIndex; + nextSymbol(); + while(isLowerCase(code[codeIndex])) + { + nextSymbol(); + } + + const std::string key = std::string(code, start, codeIndex-start); + const auto preproc = preprocessors.find(key); + + if(preproc == preprocessors.end()) + { + column -= codeIndex-start; + codeIndex = start; + state = State::FAIL; + return produceToken(TokenType::INVALID); + } + state = State::SUCCESS; + return produceToken(preproc->second, preproc->first); +} + +std::string Tokenizer::parseIdentifier() +{ + if(!isLowerCase(code[codeIndex]) && !isCapitalCase(code[codeIndex]) && code[codeIndex] != '_') + { + state = State::FAIL; + return ""; + } + + const unsigned start = codeIndex; + + nextSymbol(); + while(isLowerCase(code[codeIndex]) || isCapitalCase(code[codeIndex]) || + isDigit(code[codeIndex]) || code[codeIndex] == '_') + { + nextSymbol(); + } + + state = State::SUCCESS; + return std::string(code, start, codeIndex-start); +} + +Token Tokenizer::produceToken(TokenType type, std::string lexeme, double val) +{ + return Token{type, line, lexeme, val}; +} + +Token Tokenizer::produceToken(TokenType type) +{ + switch(type) + { + case TokenType::LEFT_PAREN: return produceToken(type, "("); + case TokenType::RIGHT_PAREN: return produceToken(type, ")"); + case TokenType::LEFT_BRACKET: return produceToken(type, "["); + case TokenType::RIGHT_BRACKET: return produceToken(type, "]"); + case TokenType::LEFT_CUR_BRAC: return produceToken(type, "{"); + case TokenType::RIGHT_CUR_BRAC: return produceToken(type, "}"); + case TokenType::PLUS: return produceToken(type, "+"); + case TokenType::MINUS: return produceToken(type, "-"); + case TokenType::MULTIPLICATION: return produceToken(type, "*"); + case TokenType::DIVIDE: return produceToken(type, "/"); + case TokenType::MODULO: return produceToken(type, "%"); + case TokenType::LESSER: return produceToken(type, "<"); + case TokenType::GREATER: return produceToken(type, ">"); + case TokenType::ASSIGN: return produceToken(type, "="); + case TokenType::SEMI_COLON: return produceToken(type, ";"); + case TokenType::QUESTION_MARK: return produceToken(type, "?"); + case TokenType::EXCLAMATION_MARK: return produceToken(type, "!"); + case TokenType::COLON: return produceToken(type, ":"); + case TokenType::BITWISE_AND: return produceToken(type, "&"); + case TokenType::BITWISE_OR: return produceToken(type, "|"); + case TokenType::BITWISE_XOR: return produceToken(type, "^"); + case TokenType::BITWISE_NOT: return produceToken(type, "~"); + case TokenType::DOT: return produceToken(type, "."); + case TokenType::SCOPE: return produceToken(type, "::"); + case TokenType::PLUS_PLUS: return produceToken(type, "++"); + case TokenType::MINUS_MINUS: return produceToken(type, "--"); + case TokenType::PTR_ARROW: return produceToken(type, "->"); + case TokenType::LEFT_BITWISE_SHIFT: return produceToken(type, "<<"); + case TokenType::RIGHT_BITWISE_SHIFT: return produceToken(type, ">>"); + case TokenType::EQUAL: return produceToken(type, "=="); + case TokenType::NOT_EQUAL: return produceToken(type, "!="); + case TokenType::LESS_EQUAL: return produceToken(type, "<="); + case TokenType::GREATER_EQUAL: return produceToken(type, ">="); + case TokenType::LOGIC_AND: return produceToken(type, "&&"); + case TokenType::LOGIC_OR: return produceToken(type, "||"); + case TokenType::MOD_EQUAL: return produceToken(type, "%="); + case TokenType::MULT_EQUAL: return produceToken(type, "*="); + case TokenType::DIV_EQUAL: return produceToken(type, "/="); + case TokenType::PLUS_EQUAL: return produceToken(type, "+="); + case TokenType::MINUS_EQUAL: return produceToken(type, "-="); + case TokenType::BIT_AND_EQUAL: return produceToken(type, "&="); + case TokenType::BIT_OR_EQUAL: return produceToken(type, "|="); + case TokenType::BIT_XOR_EQUAL: return produceToken(type, "^="); + case TokenType::LEFT_SHIFT_EQUAL: return produceToken(type, "<<="); + case TokenType::RIGHT_SHIFT_EQUAL: return produceToken(type, ">>="); + default: return produceToken(type, ""); + } +} + +Token Tokenizer::nextToken() +{ + if(isAtEOF()) + { + return produceToken(TokenType::Eof); + } + + skipWhiteSpaces(); + + // comments + std::string comment = parseComment(); + if(isStateSuccess()) + { + return produceToken(TokenType::COMMENT, comment); + } + + // preprocessors + Token preproc = parsePreprocessor(); + if(isStateSuccess()) + { + return preproc; + } + + switch(code[codeIndex]) + { + case '(': + nextSymbol(); + return produceToken(TokenType::LEFT_PAREN); + case ')': + nextSymbol(); + return produceToken(TokenType::RIGHT_PAREN); + case '[': + nextSymbol(); + return produceToken(TokenType::LEFT_BRACKET); + case ']': + nextSymbol(); + return produceToken(TokenType::RIGHT_BRACKET); + case '{': + nextSymbol(); + return produceToken(TokenType::LEFT_CUR_BRAC); + case '}': + nextSymbol(); + return produceToken(TokenType::RIGHT_CUR_BRAC); + case '+': + nextSymbol(); + if(match('+')) + { + nextSymbol(); + return produceToken(TokenType::PLUS_PLUS); + } + if(match('=')) + { + nextSymbol(); + return produceToken(TokenType::PLUS_EQUAL); + } + return produceToken(TokenType::PLUS); + case '-': + nextSymbol(); + if(match('-')) + { + nextSymbol(); + return produceToken(TokenType::MINUS_MINUS); + } + if(match('=')) + { + nextSymbol(); + return produceToken(TokenType::MINUS_EQUAL); + } + if(match('>')) + { + nextSymbol(); + return produceToken(TokenType::PTR_ARROW); + } + return produceToken(TokenType::MINUS); + case '*': + nextSymbol(); + if(match('=')) + { + nextSymbol(); + return produceToken(TokenType::MULT_EQUAL); + } + return produceToken(TokenType::MULTIPLICATION); + case '/': + nextSymbol(); + if(match('=')) + { + nextSymbol(); + return produceToken(TokenType::DIV_EQUAL); + } + return produceToken(TokenType::DIVIDE); + case '%': + nextSymbol(); + if(match('=')) + { + nextSymbol(); + return produceToken(TokenType::MOD_EQUAL); + } + return produceToken(TokenType::MODULO); + case '<': + nextSymbol(); + if(match('<')) + { + nextSymbol(); + if(match('=')) + { + nextSymbol(); + return produceToken(TokenType::LEFT_SHIFT_EQUAL); + } + return produceToken(TokenType::LEFT_BITWISE_SHIFT); + } + if(match('=')) + { + nextSymbol(); + return produceToken(TokenType::LESS_EQUAL); + } + return produceToken(TokenType::LESSER); + case '>': + nextSymbol(); + if(match('>')) + { + nextSymbol(); + if(match('=')) + { + nextSymbol(); + return produceToken(TokenType::RIGHT_SHIFT_EQUAL); + } + return produceToken(TokenType::RIGHT_BITWISE_SHIFT); + } + if(match('=')) + { + nextSymbol(); + return produceToken(TokenType::GREATER_EQUAL); + } + return produceToken(TokenType::GREATER); + case '=': + nextSymbol(); + if(match('=')) + { + nextSymbol(); + return produceToken(TokenType::EQUAL); + } + return produceToken(TokenType::ASSIGN); + case ';': + nextSymbol(); + return produceToken(TokenType::SEMI_COLON); + case '?': + nextSymbol(); + return produceToken(TokenType::QUESTION_MARK); + case '!': + nextSymbol(); + if(match('=')) + { + nextSymbol(); + return produceToken(TokenType::NOT_EQUAL); + } + return produceToken(TokenType::EXCLAMATION_MARK); + case ':': + nextSymbol(); + if(match(':')) + { + nextSymbol(); + return produceToken(TokenType::SCOPE); + } + return produceToken(TokenType::COLON); + case '&': + nextSymbol(); + if(match('&')) + { + nextSymbol(); + return produceToken(TokenType::LOGIC_AND); + } + if(match('=')) + { + nextSymbol(); + return produceToken(TokenType::BIT_AND_EQUAL); + } + return produceToken(TokenType::BITWISE_AND); + case '|': + nextSymbol(); + if(match('|')) + { + nextSymbol(); + return produceToken(TokenType::LOGIC_AND); + } + if(match('=')) + { + nextSymbol(); + return produceToken(TokenType::BIT_OR_EQUAL); + } + return produceToken(TokenType::BITWISE_OR); + case '^': + nextSymbol(); + if(match('=')) + { + nextSymbol(); + return produceToken(TokenType::BIT_XOR_EQUAL); + } + return produceToken(TokenType::BITWISE_XOR); + case '~': + nextSymbol(); + return produceToken(TokenType::BITWISE_NOT); + case '.': + nextSymbol(); + return produceToken(TokenType::DOT); + default: break; + } + + // number literals + double num = parseNumber(); + if(isStateSuccess()) + { + return produceToken(TokenType::NUMBER, "", num); + } + else if(isStateError()) + { + return produceToken(TokenType::INVALID); + } + + // string literals + std::string lex = parseString(); + if(isStateSuccess()) + { + return produceToken(TokenType::STRING, lex); + } + else if(isStateError()) + { + return produceToken(TokenType::INVALID); + } + + // keywords + Token tkn = parseKeyword(); + if(isStateSuccess()) + { + return tkn; + } + + // identifiers + std::string identifier = parseIdentifier(); + if(isStateSuccess()) + { + return produceToken(TokenType::IDENTIFIER, identifier); + } + + return produceToken(TokenType::INVALID); +} + diff --git a/homework/81625/cpp2html/src/Lexer.h b/homework/81625/cpp2html/src/Lexer.h new file mode 100644 index 0000000..92c2f53 --- /dev/null +++ b/homework/81625/cpp2html/src/Lexer.h @@ -0,0 +1,223 @@ +#ifndef LEXER_H +#define LEXER_H + +#include <vector> +#include <map> +#include <string> + +enum TokenType +{ +// Single character tokens + LEFT_PAREN = 1, // ( + RIGHT_PAREN, // ) + LEFT_BRACKET, // [ + RIGHT_BRACKET, // ] + LEFT_CUR_BRAC, // { + RIGHT_CUR_BRAC, // } + PLUS, // + + MINUS, // - + MULTIPLICATION, // * + DIVIDE, // / + MODULO, // % + LESSER, // < + GREATER, // > + ASSIGN, // = + SEMI_COLON, // ; + QUESTION_MARK, // ? + EXCLAMATION_MARK, // ! + COLON, // : + BITWISE_AND, // & + BITWISE_OR, // | + BITWISE_XOR, // ^ + BITWISE_NOT, // ~ + DOT, // . + +// Double character tokens + SCOPE, // :: + PLUS_PLUS, // ++ + MINUS_MINUS, // -- + PTR_ARROW, // -> + LEFT_BITWISE_SHIFT, // << + RIGHT_BITWISE_SHIFT,// >> + EQUAL, // == + NOT_EQUAL, // != + LESS_EQUAL, // <= + GREATER_EQUAL, // >= + LOGIC_AND, // && + LOGIC_OR, // || + MOD_EQUAL, // %= + MULT_EQUAL, // *= + DIV_EQUAL, // /= + PLUS_EQUAL, // += + MINUS_EQUAL, // -= + BIT_AND_EQUAL, // &= + BIT_OR_EQUAL, // |= + BIT_XOR_EQUAL, // ^= + +// Three character tokens + LEFT_SHIFT_EQUAL, // <<= + RIGHT_SHIFT_EQUAL, // >>= + +// Keyword Tokens + ALIGNAS, + ALIGNOF, + AND, + AND_EQ, + ASM, + AUTO, + BITAND, + BITOR, + BOOL, + BREAK, + CASE, + CATCH, + CHAR, + CHAR16_T, + CHAR32_T, + CLASS, + COMPL, + CONST, + CONSTEXPR, + CONST_CAST, + CONTINUE, + DECLTYPE, + DEFAULT, + DELETE, + DO, + DOUBLE, + DYNAMIC_CAST, + ELSE, + ENUM, + EXPLICIT, + EXPORT, + EXTERN, + FALSE, + FLOAT, + FOR, + FRIEND, + GOTO, + IF, + INLINE, + INT, + LONG, + MUTABLE, + NAMESPACE, + NEW, + NOEXCEPT, + NOT, + NOT_EQ, + NULLPTR, + OPERATOR, + OR, + OR_EQ, + PRIVATE, + PROTECTED, + PUBLIC, + REGISTER, + REINTERPRET_CAST, + RETURN, + SHORT, + SIGNED, + SIZEOF, + STATIC, + STATIC_ASSERT, + STATIC_CAST, + STRUCT, + SWITCH, + TEMPLATE, + THIS, + THREAD_LOCAL, + THROW, + TRUE, + TRY, + TYPEDEF, + TYPEID, + TYPENAME, + UNION, + UNSIGNED, + USING, + VIRTUAL, + VOID, + VOLATILE, + WCHAR_T, + WHILE, + XOR, + XOR_EQ, + + // preprocessors + PRE_DEFINE, + PRE_UNDEF, + PRE_INCLUDE, + PRE_IF, + PRE_IFDEF, + PRE_IFNDEF, + PRE_ELSE, + PRE_ELIF, + PRE_ENDIF, + PRE_LINE, + PRE_ERROR, + PRE_PRAGMA, + + NUMBER, + IDENTIFIER, + STRING, + COMMENT, + Eof, + INVALID +}; + +enum State +{ + FAIL, + SUCCESS, + ERROR +}; + +struct Token +{ + TokenType type; + unsigned line; + std::string lexeme; + double value; +}; + +class Tokenizer +{ +private: + const char* code; + unsigned line; + unsigned column; + unsigned codeIndex; + State state; + std::map<std::string, TokenType> keywords; + std::map<std::string, TokenType> preprocessors; + +public: + Tokenizer(const char* code); + Token nextToken(); + Token produceToken(TokenType type, std::string lexeme, double val = 0.0); + Token produceToken(TokenType type); + + bool isAtEOF() const; + bool match(char c) const; + bool isStateError() const; + bool isStateSuccess() const; + bool tokenize(std::vector<Token> &tokens); + + double parseNumber(); + std::string parseComment(); + std::string parseString(); + Token parseKeyword(); + Token parsePreprocessor(); + std::string parseIdentifier(); + + void skipWhiteSpaces(); + void nextSymbol(); + void prevSymbol(); + +}; + +//#include "Lexer.cpp" + +#endif + diff --git a/homework/81625/cpp2html/src/main.cpp b/homework/81625/cpp2html/src/main.cpp new file mode 100644 index 0000000..92f4d30 --- /dev/null +++ b/homework/81625/cpp2html/src/main.cpp @@ -0,0 +1,107 @@ +#include <iostream> +#include <fstream> +#include <vector> +#include "Lexer.h" + +void printTokens(std::vector<Token> &tokens) +{ + for(int i = 0;i<tokens.size();i++) + { + std::cout<<tokens[i].type<<" "<<tokens[i].lexeme <<" on line " << tokens[i].line <<std::endl; + } +} + +void cpp2html(std::vector<Token> &tokens, const char* code) +{ + std::ofstream out("../cpp2.html"); + std::string header = "<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + "<head>\n" + " <style>\n" + " body {\n" + " font-size: 20px;\n" + " }\n\n" + " .number {\n" + " color: pink;\n" + " }\n\n" + " .string {\n" + " color: blue;\n" + " }\n\n" + " .keyword {\n" + " color: purple;\n" + " font-weight: bold;\n" + " }\n\n" + " .operator {\n" + " color: red;\n" + " }\n\n" + " .comment {\n" + " color: gray;\n" + " font-style: italic;\n" + " }\n\n" + " .preprocessor {\n" + " color: green;\n" + " font-weight: bold;\n" + " }\n\n" + " </style>\n" + "</head>\n" + "<body>\n"; + out << header; + unsigned codeInd = 0; + for(int i = 0;i < tokens.size();i++) + { + while(code[codeInd] == ' ' || code[codeInd] == '\t' || code[codeInd] == '\n') + { + if(code[codeInd] == '\n') out << "<br>"; + else out << " "; + //else out << + ++codeInd; + } + if(tokens[i].type == TokenType::NUMBER) + { + out << "<span class=\"number\">" << tokens[i].value <<"</span>"; + } + else if(tokens[i].type == TokenType::STRING) + { + out << "<span class=\"string\">" << tokens[i].lexeme <<"</span>"; + } + else if(tokens[i].type == TokenType::COMMENT) + { + out << "<span class=\"comment\">" << tokens[i].lexeme <<"</span>"; + } + else if(tokens[i].type <= TokenType::RIGHT_SHIFT_EQUAL) + { + out << "<span class=\"operator\">" << tokens[i].lexeme <<"</span>"; + } + else if(tokens[i].type <= TokenType::XOR_EQ) + { + out << "<span class=\"keyword\">" << tokens[i].lexeme <<"</span>"; + } + else if(tokens[i].type <= TokenType::PRE_PRAGMA) + { + out << "<span class=\"preprocessor\">" << tokens[i].lexeme <<"</span>"; + } + else + { + out << tokens[i].lexeme; + } + codeInd += tokens[i].lexeme.length(); + } + out << "\n</body>\n</html>"; + out.close(); +} + +int main() +{ + char code[] = "#include<iostream>\nbool isCapitalCase(char c)\n{\n return c >= 'A' && c <= 'Z';\n}\nm_KeyWordsTable[\"break\"] = TokenType::Break;\n// this is a comment test\n" + "/* another one */"; + Tokenizer tokenizer(code); + std::vector<Token> tokens; + + if(tokenizer.tokenize(tokens)) + { + cpp2html(tokens, code); + } + //printTokens(tokens); + return 0; +} + |
