Add backslash escape codes - close #19

This commit is contained in:
Josh Holtrop 2024-03-29 16:45:54 -04:00
parent 1d1590dfda
commit 5b2cbe53e6
5 changed files with 132 additions and 0 deletions

View File

@ -325,9 +325,16 @@ Regular expressions can include many special characters:
* The `(` character begins a matching group. * The `(` character begins a matching group.
* The `{` character begins a count qualifier. * The `{` character begins a count qualifier.
* The `\` character escapes the following character and changes its meaning: * The `\` character escapes the following character and changes its meaning:
* The `\a` sequence matches an ASCII bell character (0x07).
* The `\b` sequence matches an ASCII backspace character (0x08).
* The `\d` sequence matches any character `0` through `9`. * The `\d` sequence matches any character `0` through `9`.
* The `\f` sequence matches an ASCII form feed character (0x0C).
* The `\n` sequence matches an ASCII new line character (0x0A).
* The `\r` sequence matches an ASCII carriage return character (0x0D).
* The `\s` sequence matches a space, horizontal tab `\t`, carriage return * The `\s` sequence matches a space, horizontal tab `\t`, carriage return
`\r`, a form feed `\f`, or a vertical tab `\v` character. `\r`, a form feed `\f`, or a vertical tab `\v` character.
* The `\t` sequence matches an ASCII tab character (0x09).
* The `\v` sequence matches an ASCII vertical tab character (0x0B).
* Any other character matches itself. * Any other character matches itself.
* The `|` character creates an alternate match. * The `|` character creates an alternate match.

View File

@ -134,8 +134,18 @@ class Propane
else else
c = @pattern.slice!(0) c = @pattern.slice!(0)
case c case c
when "a"
CharacterRangeUnit.new("\a", "\a")
when "b"
CharacterRangeUnit.new("\b", "\b")
when "d" when "d"
CharacterRangeUnit.new("0", "9") CharacterRangeUnit.new("0", "9")
when "f"
CharacterRangeUnit.new("\f", "\f")
when "n"
CharacterRangeUnit.new("\n", "\n")
when "r"
CharacterRangeUnit.new("\r", "\r")
when "s" when "s"
ccu = CharacterClassUnit.new ccu = CharacterClassUnit.new
ccu << CharacterRangeUnit.new(" ") ccu << CharacterRangeUnit.new(" ")
@ -145,6 +155,10 @@ class Propane
ccu << CharacterRangeUnit.new("\f") ccu << CharacterRangeUnit.new("\f")
ccu << CharacterRangeUnit.new("\v") ccu << CharacterRangeUnit.new("\v")
ccu ccu
when "t"
CharacterRangeUnit.new("\t", "\t")
when "v"
CharacterRangeUnit.new("\v", "\v")
else else
CharacterRangeUnit.new(c) CharacterRangeUnit.new(c)
end end

View File

@ -768,6 +768,89 @@ EOF
expect(results.stderr).to eq "" expect(results.stderr).to eq ""
expect(results.status).to eq 0 expect(results.status).to eq 0
end end
it "matches backslash escape sequences" do
case language
when "c"
write_grammar <<EOF
<<
#include <stdio.h>
>>
tokenid t;
/\\a/ <<
printf("A\\n");
>>
/\\b/ <<
printf("B\\n");
>>
/\\t/ <<
printf("T\\n");
>>
/\\n/ <<
printf("N\\n");
>>
/\\v/ <<
printf("V\\n");
>>
/\\f/ <<
printf("F\\n");
>>
/\\r/ <<
printf("R\\n");
>>
/t/ <<
return $token(t);
>>
Start -> t;
EOF
when "d"
write_grammar <<EOF
<<
import std.stdio;
>>
tokenid t;
/\\a/ <<
writeln("A");
>>
/\\b/ <<
writeln("B");
>>
/\\t/ <<
writeln("T");
>>
/\\n/ <<
writeln("N");
>>
/\\v/ <<
writeln("V");
>>
/\\f/ <<
writeln("F");
>>
/\\r/ <<
writeln("R");
>>
/t/ <<
return $token(t);
>>
Start -> t;
EOF
end
build_parser(language: language)
compile("spec/test_match_backslashes.#{language}", language: language)
results = run
expect(results.stderr).to eq ""
expect(results.status).to eq 0
verify_lines(results.stdout, [
"A",
"B",
"T",
"N",
"V",
"F",
"R",
])
end
end end
end end
end end

View File

@ -0,0 +1,13 @@
#include "testparser.h"
#include <assert.h>
#include <string.h>
int main()
{
char const * input = "\a\b\t\n\v\f\rt";
p_context_t context;
p_context_init(&context, (uint8_t const *)input, strlen(input));
assert(p_parse(&context) == P_SUCCESS);
return 0;
}

View File

@ -0,0 +1,15 @@
import testparser;
import std.stdio;
int main()
{
return 0;
}
unittest
{
string input = "\a\b\t\n\v\f\rt";
p_context_t context;
p_context_init(&context, input);
assert(p_parse(&context) == P_SUCCESS);
}