metaforce/hecl/lib/Frontend/Parser.cpp

194 lines
5.2 KiB
C++
Raw Normal View History

2015-10-09 02:08:10 +00:00
#include "HECL/HECL.hpp"
#include "HECL/Frontend.hpp"
2015-10-09 23:55:13 +00:00
/* Syntatical token parsing system */
2015-10-09 02:08:10 +00:00
namespace HECL
{
namespace Frontend
{
void Parser::skipWhitespace(std::string::const_iterator& it)
{
while (it != m_source->cend())
2015-10-09 02:08:10 +00:00
{
while (it != m_source->cend() && isspace(*it))
2015-10-09 02:08:10 +00:00
++it;
/* Skip comment line */
if (it != m_source->cend() && *it == '#')
2015-10-09 02:08:10 +00:00
{
while (it != m_source->cend() && *it != '\n')
2015-10-09 02:08:10 +00:00
++it;
if (it != m_source->cend() && *it == '\n')
2015-10-09 02:08:10 +00:00
++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)
2015-11-21 01:13:06 +00:00
return Parser::Token(TokenType::None, SourceLocation());
2015-10-09 02:08:10 +00:00
/* If parser has just been reset, emit begin token */
if (m_reset)
{
m_reset = false;
2015-11-21 01:13:06 +00:00
return Parser::Token(TokenType::SourceBegin, getLocation());
2015-10-09 02:08:10 +00:00
}
/* Skip whitespace */
skipWhitespace(m_sourceIt);
/* Check for source end */
if (m_sourceIt == m_source->cend())
2015-11-21 01:13:06 +00:00
return Parser::Token(TokenType::SourceEnd, getLocation());
2015-10-09 02:08:10 +00:00
/* Check for numeric literal */
{
char* strEnd;
2015-10-12 05:19:04 +00:00
float val = strtof(&*m_sourceIt, &strEnd);
2015-10-09 02:08:10 +00:00
if (&*m_sourceIt != strEnd)
{
2015-11-21 01:13:06 +00:00
Parser::Token tok(TokenType::NumLiteral, getLocation());
2015-10-09 02:08:10 +00:00
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)
{
2015-11-21 01:13:06 +00:00
Parser::Token tok(TokenType::VectorSwizzle, getLocation());
2015-10-09 02:08:10 +00:00
for (int i=0 ; i<count ; ++i)
{
std::string::const_iterator tmp2 = tmp + i;
tok.m_tokenString += tolower(*tmp2);
}
m_sourceIt = tmp + count;
return tok;
}
}
/* Check for arithmetic op */
if (*m_sourceIt == '+' || *m_sourceIt == '-' || *m_sourceIt == '*' || *m_sourceIt == '/')
{
2015-11-21 01:13:06 +00:00
Parser::Token tok(TokenType::ArithmeticOp, getLocation());
2015-10-09 02:08:10 +00:00
tok.m_tokenInt = *m_sourceIt;
++m_sourceIt;
return tok;
}
/* Check for parenthesis end (group or function call) */
if (*m_sourceIt == ')')
{
if (m_parenStack.empty())
{
m_diag.reportParserErr(getLocation(), "unexpected ')' while parsing");
2015-11-21 01:13:06 +00:00
return Parser::Token(TokenType::None, SourceLocation());
2015-10-09 02:08:10 +00:00
}
Parser::Token tok(m_parenStack.back(), getLocation());
++m_sourceIt;
m_parenStack.pop_back();
return tok;
}
/* Check for group start */
if (*m_sourceIt == '(')
{
2015-11-21 01:13:06 +00:00
m_parenStack.push_back(TokenType::EvalGroupEnd);
Parser::Token tok(TokenType::EvalGroupStart, getLocation());
2015-10-09 02:08:10 +00:00
++m_sourceIt;
return tok;
}
/* Check for function start */
if (isalpha(*m_sourceIt) || *m_sourceIt == '_')
{
std::string::const_iterator tmp = m_sourceIt + 1;
while (tmp != m_source->cend() && (isalnum(*tmp) || *tmp == '_') && *tmp != '(')
++tmp;
std::string::const_iterator nameEnd = tmp;
skipWhitespace(tmp);
if (*tmp == '(')
{
2015-11-21 01:13:06 +00:00
Parser::Token tok(TokenType::FunctionStart, getLocation());
2015-10-09 02:08:10 +00:00
tok.m_tokenString.assign(m_sourceIt, nameEnd);
m_sourceIt = tmp + 1;
2015-11-21 01:13:06 +00:00
m_parenStack.push_back(TokenType::FunctionEnd);
2015-10-09 02:08:10 +00:00
return tok;
}
}
/* Check for function arg delimitation */
if (*m_sourceIt == ',')
{
2015-11-21 01:13:06 +00:00
if (m_parenStack.empty() || m_parenStack.back() != TokenType::FunctionEnd)
2015-10-09 02:08:10 +00:00
{
m_diag.reportParserErr(getLocation(), "unexpected ',' while parsing");
2015-11-21 01:13:06 +00:00
return Parser::Token(TokenType::None, SourceLocation());
2015-10-09 02:08:10 +00:00
}
2015-11-21 01:13:06 +00:00
Parser::Token tok(TokenType::FunctionArgDelim, getLocation());
2015-10-09 02:08:10 +00:00
++m_sourceIt;
return tok;
}
/* Error condition if reached */
m_diag.reportParserErr(getLocation(), "unexpected token while parsing");
2015-11-21 01:13:06 +00:00
return Parser::Token(TokenType::None, SourceLocation());
2015-10-09 02:08:10 +00:00
}
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};
}
}
}