diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 60cdc87..b0cfa13 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -250,7 +250,12 @@ namespace gcc void generic_visitor::visit(source::number_literal *literal) { - this->current_expression = build_int_cst_type(integer_type_node, literal->number()); + this->current_expression = build_int_cst(integer_type_node, literal->number()); + } + + void generic_visitor::visit(source::number_literal *literal) + { + this->current_expression = build_int_cstu(unsigned_type_node, literal->number()); } void generic_visitor::visit(source::number_literal *literal) diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index ea280dd..8169126 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -41,6 +41,7 @@ namespace gcc void visit(source::procedure_definition *definition) override; void visit(source::call_expression *statement) override; void visit(source::number_literal *literal) override; + void visit(source::number_literal *literal) override; void visit(source::number_literal *literal) override; void visit(source::number_literal *boolean) override; void visit(source::number_literal *character) override; diff --git a/include/elna/source/ast.h b/include/elna/source/ast.h index fa61997..c3cae7b 100644 --- a/include/elna/source/ast.h +++ b/include/elna/source/ast.h @@ -94,6 +94,7 @@ namespace source virtual void visit(field_access_expression *is_field_access) = 0; virtual void visit(dereference_expression *is_dereference) = 0; virtual void visit(number_literal *) = 0; + virtual void visit(number_literal *) = 0; virtual void visit(number_literal *) = 0; virtual void visit(number_literal *) = 0; virtual void visit(number_literal *) = 0; @@ -130,6 +131,7 @@ namespace source virtual void visit(field_access_expression *expression) override; virtual void visit(dereference_expression *expression) override; virtual void visit(number_literal *) override; + virtual void visit(number_literal *) override; virtual void visit(number_literal *) override; virtual void visit(number_literal *) override; virtual void visit(number_literal *) override; diff --git a/include/elna/source/driver.h b/include/elna/source/driver.h index 36ba93a..de4dead 100644 --- a/include/elna/source/driver.h +++ b/include/elna/source/driver.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include "elna/source/ast.h" #include "location.hh" @@ -37,5 +38,7 @@ namespace source void error(const yy::location& loc, const std::string& message); const std::list>& errors() const noexcept; }; + + std::optional escape_char(char escape); } } diff --git a/source/ast.cc b/source/ast.cc index b082640..13388ee 100644 --- a/source/ast.cc +++ b/source/ast.cc @@ -167,6 +167,10 @@ namespace source { } + void empty_visitor::visit(number_literal *) + { + } + void empty_visitor::visit(number_literal *) { } diff --git a/source/driver.cc b/source/driver.cc index 4b35d27..c58324f 100644 --- a/source/driver.cc +++ b/source/driver.cc @@ -40,5 +40,38 @@ namespace source { return m_errors; } + + std::optional escape_char(char escape) + { + switch (escape) + { + case 'n': + return std::make_optional('\n'); + case 'a': + return std::make_optional('\a'); + case 'b': + return std::make_optional('\b'); + case 't': + return std::make_optional('\t'); + case 'f': + return std::make_optional('\f'); + case 'r': + return std::make_optional('\r'); + case 'v': + return std::make_optional('\v'); + case '\\': + return std::make_optional('\\'); + case '\'': + return std::make_optional('\''); + case '"': + return std::make_optional('"'); + case '?': + return std::make_optional('\?'); + case '0': + return std::make_optional('\0'); + default: + return std::nullopt; + } + } } } diff --git a/source/lexer.ll b/source/lexer.ll index 2711b39..c056d94 100644 --- a/source/lexer.ll +++ b/source/lexer.ll @@ -106,6 +106,9 @@ return { [A-Za-z_][A-Za-z0-9_]* { return yy::parser::make_IDENTIFIER(yytext, this->location); } +[0-9]+u { + return yy::parser::make_WORD(strtoul(yytext, NULL, 10), this->location); + } [0-9]+ { return yy::parser::make_INTEGER(strtol(yytext, NULL, 10), this->location); } @@ -113,7 +116,7 @@ return { return yy::parser::make_FLOAT(strtof(yytext, NULL), this->location); } '[[:print:]]' { - if (yytext[1] == '\\') + if (yytext[1] == '\\' || yytext[1] == '\'') { REJECT; } @@ -122,45 +125,66 @@ return { return yy::parser::make_CHARACTER(std::string(yytext, 1, 1), this->location); } } -'\\x[0-9a-fA-F]{2}' { +'\\x[0-9a-fA-F]{1,2}' { char character = static_cast(std::stoi(yytext + 3, nullptr, 16)); return yy::parser::make_CHARACTER(std::string(&character, 1), this->location); } '\\[0nabtfrv\\'"?]' { - switch (yytext[2]) + std::optional escape = source::escape_char(yytext[2]); + if (escape.has_value()) + { + return yy::parser::make_CHARACTER(std::string(&escape.value(), 1), this->location); + } + else { - case 'n': - return yy::parser::make_CHARACTER(std::string("\n"), this->location); - case 'a': - return yy::parser::make_CHARACTER(std::string("\a"), this->location); - case 'b': - return yy::parser::make_CHARACTER(std::string("\b"), this->location); - case 't': - return yy::parser::make_CHARACTER(std::string("\t"), this->location); - case 'f': - return yy::parser::make_CHARACTER(std::string("\f"), this->location); - case 'r': - return yy::parser::make_CHARACTER(std::string("\r"), this->location); - case 'v': - return yy::parser::make_CHARACTER(std::string("\v"), this->location); - case '\\': - return yy::parser::make_CHARACTER(std::string("\\"), this->location); - case '\'': - return yy::parser::make_CHARACTER(std::string("'"), this->location); - case '"': - return yy::parser::make_CHARACTER(std::string("\""), this->location); - case '?': - return yy::parser::make_CHARACTER(std::string("\?"), this->location); - case '0': - return yy::parser::make_CHARACTER(std::string("\0", 1), this->location); - default: REJECT; } } -\"[^\"]*\" { - return yy::parser::make_STRING( - std::string(yytext, 1, strlen(yytext) - 2), this->location); +\"[[:print:]]*\" { + std::string result; + const char *current_position = yytext + 1; + + while (*current_position != '\0') + { + if (*current_position == '\\' && *(current_position + 1) == 'x') + { + current_position += 2; + + std::size_t processed; + char character = static_cast(std::stoi(current_position, &processed, 16)); + if (processed == 0) + { + REJECT; + } + else + { + current_position += processed - 1; + result.push_back(character); + } + } + else if (*current_position == '\\') + { + ++current_position; + + std::optional escape = source::escape_char(*current_position); + if (escape.has_value()) + { + result.push_back(escape.value()); + } + else + { + REJECT; + } + } + else + { + result.push_back(*current_position); + } + ++current_position; + } + result.pop_back(); + return yy::parser::make_STRING(result, this->location); } \( { return yy::parser::make_LEFT_PAREN(this->location); diff --git a/source/parser.yy b/source/parser.yy index 8393b31..e7aa924 100644 --- a/source/parser.yy +++ b/source/parser.yy @@ -58,6 +58,7 @@ %token IDENTIFIER "identifier" %token INTEGER "integer" +%token WORD "word" %token FLOAT "float" %token CHARACTER "character" %token STRING "string" @@ -208,6 +209,10 @@ literal: { $$ = new elna::source::number_literal(elna::source::make_position(@1), $1); } + | WORD + { + $$ = new elna::source::number_literal(elna::source::make_position(@1), $1); + } | FLOAT { $$ = new elna::source::number_literal(elna::source::make_position(@1), $1);