#include "HECL/HECL.hpp" #include "HECL/Frontend.hpp" /* Syntatical token parsing system */ namespace HECL { namespace Frontend { void Parser::skipWhitespace(std::string::const_iterator& it) { while (it != m_source->cend()) { while (it != m_source->cend() && isspace(*it)) ++it; /* Skip comment line */ if (it != m_source->cend() && *it == '#') { while (it != m_source->cend() && *it != '\n') ++it; if (it != m_source->cend() && *it == '\n') ++it; continue; } break; } } void Parser::reset(const std::string& source) { m_source = &source; m_sourceIt = m_source->cbegin(); m_parenStack.clear(); m_reset = true; } Parser::Token Parser::consumeToken() { if (!m_source) return Parser::Token(TokenType::None, SourceLocation()); /* If parser has just been reset, emit begin token */ if (m_reset) { m_reset = false; return Parser::Token(TokenType::SourceBegin, getLocation()); } /* Skip whitespace */ skipWhitespace(m_sourceIt); /* Check for source end */ if (m_sourceIt == m_source->cend()) return Parser::Token(TokenType::SourceEnd, getLocation()); /* Check for numeric literal */ { char* strEnd; float val = strtof(&*m_sourceIt, &strEnd); if (&*m_sourceIt != strEnd) { Parser::Token tok(TokenType::NumLiteral, getLocation()); tok.m_tokenFloat = val; m_sourceIt += (strEnd - &*m_sourceIt); return tok; } } /* Check for swizzle op */ if (*m_sourceIt == '.') { int count = 0; std::string::const_iterator tmp = m_sourceIt + 1; if (tmp != m_source->cend()) { for (int i=0 ; i<4 ; ++i) { std::string::const_iterator tmp2 = tmp + i; if (tmp2 == m_source->cend()) break; char ch = tolower(*tmp2); if (ch >= 'w' && ch <= 'z') ++count; else if (ch == 'r' || ch == 'g' || ch == 'b' || ch == 'a') ++count; else break; } } if (count) { Parser::Token tok(TokenType::VectorSwizzle, getLocation()); for (int i=0 ; icend() && (isalnum(*tmp) || *tmp == '_') && *tmp != '(') ++tmp; std::string::const_iterator nameEnd = tmp; skipWhitespace(tmp); if (*tmp == '(') { Parser::Token tok(TokenType::FunctionStart, getLocation()); tok.m_tokenString.assign(m_sourceIt, nameEnd); m_sourceIt = tmp + 1; m_parenStack.push_back(TokenType::FunctionEnd); return tok; } } /* Check for function arg delimitation */ if (*m_sourceIt == ',') { if (m_parenStack.empty() || m_parenStack.back() != TokenType::FunctionEnd) { m_diag.reportParserErr(getLocation(), "unexpected ',' while parsing"); return Parser::Token(TokenType::None, SourceLocation()); } Parser::Token tok(TokenType::FunctionArgDelim, getLocation()); ++m_sourceIt; return tok; } /* Error condition if reached */ m_diag.reportParserErr(getLocation(), "unexpected token while parsing"); return Parser::Token(TokenType::None, SourceLocation()); } SourceLocation Parser::getLocation() const { if (!m_source) return SourceLocation(); std::string::const_iterator it = m_source->cbegin(); int line = 0; int col = 0; for (; it != m_sourceIt ; ++it) { ++col; if (*it == '\n') { ++line; col = 0; } } return {line+1, col+1}; } } }