Commit 59626472 authored by Alastair Robertson's avatar Alastair Robertson

Add support for escape characters in strings

parent 5a73475e
......@@ -110,7 +110,7 @@ Functions:
- `count()` - count the number of times this function is called
- `delete()` - delete the map element this is assigned to
- `str(char *s)` - returns the string pointed to by `s`
- `printf(char *fmt, ...)` - write to stdout (support for escape characters is coming)
- `printf(char *fmt, ...)` - write to stdout
# Building
......
......@@ -58,36 +58,31 @@ void perf_event_printer(void *cb_cookie, void *data, int size)
arg_data += arg.size;
}
// TODO remove when \n works with the lexer
std::string fmt_newline(fmt);
fmt_newline += "\n";
switch (args.size())
{
case 0:
printf(fmt_newline.c_str());
printf(fmt);
break;
case 1:
printf(fmt_newline.c_str(), arg_values.at(0));
printf(fmt, arg_values.at(0));
break;
case 2:
printf(fmt_newline.c_str(), arg_values.at(0), arg_values.at(1));
printf(fmt, arg_values.at(0), arg_values.at(1));
break;
case 3:
printf(fmt_newline.c_str(), arg_values.at(0), arg_values.at(1),
arg_values.at(2));
printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2));
break;
case 4:
printf(fmt_newline.c_str(), arg_values.at(0), arg_values.at(1),
arg_values.at(2), arg_values.at(3));
printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(3));
break;
case 5:
printf(fmt_newline.c_str(), arg_values.at(0), arg_values.at(1),
arg_values.at(2), arg_values.at(3), arg_values.at(4));
printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(3), arg_values.at(4));
break;
case 6:
printf(fmt_newline.c_str(), arg_values.at(0), arg_values.at(1),
arg_values.at(2), arg_values.at(3), arg_values.at(4), arg_values.at(5));
printf(fmt, arg_values.at(0), arg_values.at(1), arg_values.at(2),
arg_values.at(3), arg_values.at(4), arg_values.at(5));
break;
default:
abort();
......
......@@ -24,6 +24,7 @@ public:
void error(const location &l, const std::string &m)
{
std::cerr << l << ": " << m << std::endl;
exit(-1);
}
void error(const std::string &m)
......
......@@ -9,6 +9,7 @@
#define yywrap(x) 1
static bpftrace::location loc;
static std::string string_buffer;
#define YY_USER_ACTION loc.columns(yyleng);
#define yyterminate() return bpftrace::Parser::make_END(loc)
......@@ -24,7 +25,7 @@ hspace [ \t]
vspace [\n\r]
space {hspace}|{vspace}
path :(\\.|[_\-\./a-zA-Z0-9])*:
string \"(\\.|[^\\"])*\"
%x STR
%%
......@@ -38,7 +39,6 @@ string \"(\\.|[^\\"])*\"
{ident} { return Parser::make_IDENT(yytext, loc); }
{path} { return Parser::make_PATH(yytext, loc); }
{string} { return Parser::make_STRING(yytext, loc); }
{map} { return Parser::make_MAP(yytext, loc); }
{var} { return Parser::make_VAR(yytext, loc); }
{int} { return Parser::make_INT(strtoul(yytext, NULL, 0), loc); }
......@@ -72,6 +72,21 @@ string \"(\\.|[^\\"])*\"
"!" { return Parser::make_LNOT(loc); }
"~" { return Parser::make_BNOT(loc); }
. { driver.error(loc, std::string("invalid character: ")+std::string(yytext)); exit(1); }
\" { BEGIN(STR); string_buffer.clear(); }
<STR>\" { BEGIN(INITIAL); return Parser::make_STRING(string_buffer, loc); }
<STR>[^\\\n\"]+ { string_buffer += std::string(yytext); }
<STR>\\n { string_buffer += std::string("\n"); }
<STR>\\t { string_buffer += std::string("\t"); }
<STR>\\\" { string_buffer += std::string("\""); }
<STR>\\\\ { string_buffer += std::string("\\"); }
<STR>\n { driver.error(loc, std::string("unterminated string")); }
<STR><<EOF>> { driver.error(loc, std::string("unterminated string")); }
<STR>\\. { driver.error(loc, std::string("invalid escape character '") +
std::string(yytext) + std::string("'")); }
<STR>. { driver.error(loc, std::string("invalid character '") +
std::string(yytext) + std::string("'")); }
. { driver.error(loc, std::string("invalid character '") +
std::string(yytext) + std::string("'")); }
%%
......@@ -85,8 +85,6 @@ void yyerror(bpftrace::Driver &driver, const char *s);
%type <ast::Variable *> var
%type <ast::ExpressionList *> vargs
%printer { yyoutput << %%; } <*>;
%right ASSIGN
%left LOR
%left LAND
......@@ -130,7 +128,7 @@ stmt : expr { $$ = new ast::ExprStatement($1); }
;
expr : INT { $$ = new ast::Integer($1); }
| STRING { $$ = new ast::String($1.substr(1, $1.size()-2)); }
| STRING { $$ = new ast::String($1); }
| IDENT { $$ = new ast::Builtin($1); }
| map { $$ = $1; }
| var { $$ = $1; }
......
#include <regex>
#include "printer.h"
#include "ast.h"
......@@ -13,7 +15,14 @@ void Printer::visit(Integer &integer)
void Printer::visit(String &string)
{
std::string indent(depth_, ' ');
out_ << indent << "string: " << string.str << std::endl;
std::string str = string.str;
str = std::regex_replace(str, std::regex("\\\\"), "\\\\");
str = std::regex_replace(str, std::regex("\n"), "\\n");
str = std::regex_replace(str, std::regex("\t"), "\\t");
str = std::regex_replace(str, std::regex("\""), "\\\"");
out_ << indent << "string: " << str << std::endl;
}
void Printer::visit(Builtin &builtin)
......
......@@ -40,6 +40,7 @@ std::string verify_format_string(const std::string &fmt, std::vector<SizedType>
case 'u':
case 'x':
case 'X':
case 'p':
token_type = Type::integer;
break;
case 's':
......
......@@ -5,6 +5,8 @@
#include "printer.h"
namespace bpftrace {
namespace test {
namespace parser {
using Printer = ast::Printer;
......@@ -202,4 +204,14 @@ TEST(Parser, uprobe)
" int: 1\n");
}
TEST(Parser, escape_chars)
{
test("kprobe:sys_open { \"newline\\nand tab\\tbackslash\\\\quote\\\"here\" }",
"Program\n"
" kprobe:sys_open\n"
" string: newline\\nand tab\\tbackslash\\\\quote\\\"here\n");
}
} // namespace parser
} // namespace test
} // namespace bpftrace
......@@ -5,6 +5,8 @@
#include "semantic_analyser.h"
namespace bpftrace {
namespace test {
namespace semantic_analyser {
class MockBPFtrace : public BPFtrace {
public:
......@@ -185,4 +187,6 @@ TEST(semantic_analyser, printf_format_multi)
test("kprobe:f { printf(\"%d %s %d\", 1, 2, \"mystr\") }", 10);
}
} // namespace semantic_analyser
} // namespace test
} // namespace bpftrace
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment