Implement character escape sequences
This commit is contained in:
parent
156506e8fa
commit
0dc95d4466
34
example.elna
34
example.elna
@ -12,6 +12,9 @@ type
|
|||||||
dummy: Int
|
dummy: Int
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
const
|
||||||
|
SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2;
|
||||||
|
|
||||||
proc test_array();
|
proc test_array();
|
||||||
var a: T, x: Int;
|
var a: T, x: Int;
|
||||||
begin
|
begin
|
||||||
@ -66,19 +69,6 @@ begin
|
|||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
proc test_not();
|
|
||||||
var x: Bool;
|
|
||||||
begin
|
|
||||||
x := false;
|
|
||||||
|
|
||||||
writei("");
|
|
||||||
if not x then
|
|
||||||
writei("Test not true.")
|
|
||||||
else
|
|
||||||
writei("Test not false")
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
|
|
||||||
proc test_param(d: Int, e: Int);
|
proc test_param(d: Int, e: Int);
|
||||||
begin
|
begin
|
||||||
writei("");
|
writei("");
|
||||||
@ -124,14 +114,14 @@ proc fseek(stream: pointer to FILE, off: Int, whence: Int): Int; extern;
|
|||||||
proc ftell(stream: pointer to FILE): Int; extern;
|
proc ftell(stream: pointer to FILE): Int; extern;
|
||||||
proc fread(ptr: pointer to Char, size: Int, nmemb: Int, stream: pointer to FILE): Int; extern;
|
proc fread(ptr: pointer to Char, size: Int, nmemb: Int, stream: pointer to FILE): Int; extern;
|
||||||
proc write(fd: Int, buf: pointer to Char, count: Int): Int; extern;
|
proc write(fd: Int, buf: pointer to Char, count: Int): Int; extern;
|
||||||
|
|
||||||
proc malloc(size: Int): pointer to Char; extern;
|
proc malloc(size: Int): pointer to Char; extern;
|
||||||
proc free(ptr: pointer to Char); extern;
|
proc free(ptr: pointer to Char); extern;
|
||||||
|
proc calloc(nmemb: Int, size: Int): pointer to Char; extern;
|
||||||
|
|
||||||
proc memset(ptr: pointer to Char, c: Int, n: Int): pointer to Char; extern;
|
proc memset(ptr: pointer to Char, c: Int, n: Int): pointer to Char; extern;
|
||||||
|
|
||||||
proc read_source(filename: String): pointer to Char;
|
proc read_source(filename: String): pointer to Char;
|
||||||
const
|
|
||||||
-- Bug: The procedure doesn't see global constants.
|
|
||||||
SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2;
|
|
||||||
var
|
var
|
||||||
input_file: pointer to FILE,
|
input_file: pointer to FILE,
|
||||||
source_size: Int,
|
source_size: Int,
|
||||||
@ -143,8 +133,7 @@ begin
|
|||||||
source_size := ftell(input_file);
|
source_size := ftell(input_file);
|
||||||
fseek(input_file, 0, SEEK_SET);
|
fseek(input_file, 0, SEEK_SET);
|
||||||
|
|
||||||
input := malloc(source_size + 1);
|
input := calloc(source_size + 1, 1);
|
||||||
memset(input, 0, source_size + 1);
|
|
||||||
fread(input, source_size, 1, input_file);
|
fread(input, source_size, 1, input_file);
|
||||||
|
|
||||||
fclose(input_file);
|
fclose(input_file);
|
||||||
@ -152,12 +141,6 @@ begin
|
|||||||
return input
|
return input
|
||||||
end;
|
end;
|
||||||
|
|
||||||
-- Bug: "while not is_eof(…) do" is a syntax error.
|
|
||||||
proc is_not_eof(buffer: pointer to Int): Bool;
|
|
||||||
begin
|
|
||||||
return buffer^ /= 0
|
|
||||||
end;
|
|
||||||
|
|
||||||
proc compile();
|
proc compile();
|
||||||
var
|
var
|
||||||
input: pointer to Char,
|
input: pointer to Char,
|
||||||
@ -166,7 +149,7 @@ begin
|
|||||||
input := read_source("example.elna");
|
input := read_source("example.elna");
|
||||||
|
|
||||||
input_pointer := input;
|
input_pointer := input;
|
||||||
while is_not_eof(input_pointer) do
|
while input_pointer^ /= '\0' do
|
||||||
write(0, input_pointer, 1);
|
write(0, input_pointer, 1);
|
||||||
input_pointer := input_pointer + 1
|
input_pointer := input_pointer + 1
|
||||||
end;
|
end;
|
||||||
@ -179,7 +162,6 @@ begin
|
|||||||
test_array();
|
test_array();
|
||||||
test_record();
|
test_record();
|
||||||
test_if();
|
test_if();
|
||||||
test_not();
|
|
||||||
test_param(8, 7);
|
test_param(8, 7);
|
||||||
test_const_char();
|
test_const_char();
|
||||||
writei(test_return_int());
|
writei(test_return_int());
|
||||||
|
@ -124,11 +124,14 @@ namespace gcc
|
|||||||
|
|
||||||
void generic_visitor::visit(source::program *program)
|
void generic_visitor::visit(source::program *program)
|
||||||
{
|
{
|
||||||
|
for (const auto definition : program->value_definitions)
|
||||||
|
{
|
||||||
|
definition->accept(this);
|
||||||
|
}
|
||||||
for (const auto& constant : program->type_definitions)
|
for (const auto& constant : program->type_definitions)
|
||||||
{
|
{
|
||||||
constant->accept(this);
|
constant->accept(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
tree parameter_types[] = {
|
tree parameter_types[] = {
|
||||||
integer_type_node,
|
integer_type_node,
|
||||||
build_pointer_type(build_pointer_type(char_type_node))
|
build_pointer_type(build_pointer_type(char_type_node))
|
||||||
@ -141,10 +144,6 @@ namespace gcc
|
|||||||
|
|
||||||
enter_scope();
|
enter_scope();
|
||||||
|
|
||||||
for (const auto definition : program->value_definitions)
|
|
||||||
{
|
|
||||||
definition->accept(this);
|
|
||||||
}
|
|
||||||
for (const auto body_statement : program->body)
|
for (const auto body_statement : program->body)
|
||||||
{
|
{
|
||||||
body_statement->accept(this);
|
body_statement->accept(this);
|
||||||
|
@ -736,7 +736,7 @@ namespace source
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
unary_expression(const struct position position, expression *operand,
|
unary_expression(const struct position position, expression *operand,
|
||||||
const unsigned char operation);
|
const unary_operator operation);
|
||||||
|
|
||||||
virtual void accept(parser_visitor *visitor) override;
|
virtual void accept(parser_visitor *visitor) override;
|
||||||
expression& operand();
|
expression& operand();
|
||||||
|
@ -41,6 +41,8 @@ namespace source
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using symbol_ptr = std::shared_ptr<info<T>>;
|
using symbol_ptr = std::shared_ptr<info<T>>;
|
||||||
|
using iterator = typename std::unordered_map<std::string, symbol_ptr>::iterator;
|
||||||
|
using const_iterator = typename std::unordered_map<std::string, symbol_ptr>::const_iterator;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, symbol_ptr> entries;
|
std::unordered_map<std::string, symbol_ptr> entries;
|
||||||
@ -57,6 +59,26 @@ namespace source
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return entries.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return entries.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator cbegin() const
|
||||||
|
{
|
||||||
|
return entries.cbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator cend() const
|
||||||
|
{
|
||||||
|
return entries.cend();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks for symbol in the table by name. Returns nullptr if the symbol
|
* Looks for symbol in the table by name. Returns nullptr if the symbol
|
||||||
* can not be found.
|
* can not be found.
|
||||||
|
@ -752,20 +752,9 @@ namespace source
|
|||||||
}
|
}
|
||||||
|
|
||||||
unary_expression::unary_expression(const struct position position, expression *operand,
|
unary_expression::unary_expression(const struct position position, expression *operand,
|
||||||
const unsigned char operation)
|
const unary_operator operation)
|
||||||
: expression(position), m_operand(std::move(operand))
|
: expression(position), m_operand(std::move(operand)), m_operator(operation)
|
||||||
{
|
{
|
||||||
switch (operation)
|
|
||||||
{
|
|
||||||
case '@':
|
|
||||||
this->m_operator = unary_operator::reference;
|
|
||||||
break;
|
|
||||||
case '!':
|
|
||||||
this->m_operator = unary_operator::negation;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
__builtin_unreachable();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void unary_expression::accept(parser_visitor *visitor)
|
void unary_expression::accept(parser_visitor *visitor)
|
||||||
|
@ -112,13 +112,50 @@ return {
|
|||||||
[0-9]+\.[0-9] {
|
[0-9]+\.[0-9] {
|
||||||
return yy::parser::make_FLOAT(strtof(yytext, NULL), this->location);
|
return yy::parser::make_FLOAT(strtof(yytext, NULL), this->location);
|
||||||
}
|
}
|
||||||
'[^']' {
|
'[[:print:]]' {
|
||||||
return yy::parser::make_CHARACTER(
|
if (yytext[1] == '\\')
|
||||||
std::string(yytext, 1, strlen(yytext) - 2), this->location);
|
{
|
||||||
|
REJECT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return yy::parser::make_CHARACTER(std::string(yytext, 1, 1), this->location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'\\[0nabtfrv\\'"?]' {
|
||||||
|
switch (yytext[2])
|
||||||
|
{
|
||||||
|
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(
|
return yy::parser::make_STRING(
|
||||||
std::string(yytext, 1, strlen(yytext) - 2), this->location);
|
std::string(yytext, 1, strlen(yytext) - 2), this->location);
|
||||||
}
|
}
|
||||||
\( {
|
\( {
|
||||||
return yy::parser::make_LEFT_PAREN(this->location);
|
return yy::parser::make_LEFT_PAREN(this->location);
|
||||||
|
@ -227,6 +227,7 @@ literal:
|
|||||||
pointer:
|
pointer:
|
||||||
literal { $$ = $1; }
|
literal { $$ = $1; }
|
||||||
| designator_expression { $$ = $1; }
|
| designator_expression { $$ = $1; }
|
||||||
|
| call_expression { $$ = $1; }
|
||||||
| LEFT_PAREN expression RIGHT_PAREN { $$ = std::move($2); }
|
| LEFT_PAREN expression RIGHT_PAREN { $$ = std::move($2); }
|
||||||
summand:
|
summand:
|
||||||
factor { $$ = std::move($1); }
|
factor { $$ = std::move($1); }
|
||||||
@ -243,11 +244,13 @@ summand:
|
|||||||
factor:
|
factor:
|
||||||
AT pointer
|
AT pointer
|
||||||
{
|
{
|
||||||
$$ = new elna::source::unary_expression(elna::source::make_position(@1), $2, '@');
|
$$ = new elna::source::unary_expression(elna::source::make_position(@1), $2,
|
||||||
|
elna::source::unary_operator::reference);
|
||||||
}
|
}
|
||||||
| NOT pointer
|
| NOT pointer
|
||||||
{
|
{
|
||||||
$$ = new elna::source::unary_expression(elna::source::make_position(@1), $2, '!');
|
$$ = new elna::source::unary_expression(elna::source::make_position(@1), $2,
|
||||||
|
elna::source::unary_operator::negation);
|
||||||
}
|
}
|
||||||
| pointer { $$ = $1; }
|
| pointer { $$ = $1; }
|
||||||
comparand:
|
comparand:
|
||||||
@ -296,7 +299,6 @@ expression:
|
|||||||
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, 'o');
|
$$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, 'o');
|
||||||
}
|
}
|
||||||
| logical_operand { $$ = $1; }
|
| logical_operand { $$ = $1; }
|
||||||
| call_expression { $$ = $1; }
|
|
||||||
expressions:
|
expressions:
|
||||||
expression COMMA expressions
|
expression COMMA expressions
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user