aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--boot/driver.cc25
-rw-r--r--boot/lexer.ll22
-rw-r--r--include/elna/boot/driver.h7
3 files changed, 48 insertions, 6 deletions
diff --git a/boot/driver.cc b/boot/driver.cc
index 374bcc9..24a11fa 100644
--- a/boot/driver.cc
+++ b/boot/driver.cc
@@ -66,6 +66,29 @@ namespace elna::boot
}
}
+ void normalize_newlines(std::string& string)
+ {
+ std::string result;
+ auto length = string.size();
+
+ for (std::size_t i = 0; i < length; ++i)
+ {
+ if (string[i] == '\r')
+ {
+ if (i + 1 < length && string[i + 1] == '\n')
+ {
+ ++i; // Skip \n in \r\n pairs.
+ }
+ result.push_back('\n');
+ }
+ else
+ {
+ result.push_back(string[i]);
+ }
+ }
+ string = std::move(result);
+ }
+
std::optional<std::string> escape_string(const char *escape)
{
std::string result;
@@ -73,7 +96,7 @@ namespace elna::boot
while (*current_position != '\0')
{
- if (*current_position == '\\' && *(current_position + 1) == 'x')
+ if (*current_position == '\\' && (*(current_position + 1) == 'x' || *(current_position + 1) == 'X'))
{
current_position += 2;
diff --git a/boot/lexer.ll b/boot/lexer.ll
index faae3d7..e84af85 100644
--- a/boot/lexer.ll
+++ b/boot/lexer.ll
@@ -17,7 +17,19 @@ along with GCC; see the file COPYING3. If not see
%{
#define YY_NO_UNISTD_H
-#define YY_USER_ACTION this->location.columns(yyleng);
+#define YY_USER_ACTION do { \
+ for (int i = 0; i < yyleng; i++) \
+ { \
+ if (yytext[i] == '\n') \
+ { \
+ this->location.lines(1); \
+ } \
+ else \
+ { \
+ this->location.columns(1); \
+ } \
+ } \
+} while (0);
#include <sstream>
#include "parser.hh"
@@ -47,7 +59,6 @@ BIGIT [01]
[^*\n]+ ; /* Eat comment in chunks. */
\* ; /* Eat the lone star. */
\n+ {
- this->location.lines(yyleng);
this->location.step();
}
}
@@ -56,7 +67,6 @@ BIGIT [01]
this->location.step();
}
\n+ {
- this->location.lines(yyleng);
}
if {
return yy::parser::make_IF(this->location);
@@ -220,20 +230,22 @@ of {
return yy::parser::make_FLOAT(result, this->location);
}
}
-'[[:print:]]+' {
+'([[:print:]]{-}['\\]|[[:blank:]]|\n|\r|\\.|\\\n)+' {
std::optional<std::string> result = escape_string(yytext);
if (!result.has_value() || result.value().size() != 1)
{
REJECT;
}
+ normalize_newlines(result.value());
return yy::parser::make_CHARACTER(result.value(), this->location);
}
-\"[[:print:]]*\" {
+\"([[:print:]]{-}[\"\\]|[[:blank:]]|\n|\r|\\.|\\\n)*\" {
std::optional<std::string> result = escape_string(yytext);
if (!result.has_value())
{
REJECT;
}
+ normalize_newlines(result.value());
return yy::parser::make_STRING(result.value(), this->location);
}
\( {
diff --git a/include/elna/boot/driver.h b/include/elna/boot/driver.h
index ef5be81..34a8c99 100644
--- a/include/elna/boot/driver.h
+++ b/include/elna/boot/driver.h
@@ -46,5 +46,12 @@ namespace elna::boot
constexpr char escape_invalid_char = '\xff';
char escape_char(char escape);
+ /**
+ * Replaces both \r\n sequences and lone \r characters with \n.
+ * Modifies the original input.
+ *
+ * \param string Text to normalize.
+ */
+ void normalize_newlines(std::string& string);
std::optional<std::string> escape_string(const char *escape);
}