Merge pull request #636 from steveicarus/string-special-characters

String special characters
This commit is contained in:
Stephen Williams 2022-03-05 19:12:16 -08:00 committed by GitHub
commit ede341410f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 178 additions and 2 deletions

View File

@ -0,0 +1,45 @@
module main;
string foo;
int error_count;
task check_char(input int idx, input [7:0] val);
if (foo[idx] !== val) begin
$display("FAILED: foo[%0d]==%02h, expecting %02h",
idx, foo[idx], val);
error_count = error_count+1;
end
endtask // check_char
initial begin
// These are the special charasters in strings as defined by
// IEEE Std 1800-2017: 5.9.1 Special characters in strings.
// The string assignment is governed by:
// IEEE Std 1800-2017: 6.16 String data type
foo = "abc\n\t\\\"\v\f\a\001\002\x03\x04";
error_count = 0;
check_char(0, 8'h61); // 'a'
check_char(1, 8'h62); // 'b'
check_char(2, 8'h63); // 'c'
check_char(3, 8'h0a); // '\n'
check_char(4, 8'h09); // '\t'
check_char(5, 8'h5c); // '\\'
check_char(6, 8'h22); // '\"'
check_char(7, 8'h0b); // '\v'
check_char(8, 8'h0c); // '\f'
check_char(9, 8'h07); // '\a'
check_char(10, 8'h01); // '\001'
check_char(11, 8'h02); // '\002'
check_char(12, 8'h03); // '\x03'
check_char(13, 8'h04); // '\x04'
if (foo.len() !== 14) begin
$display("FAILED: foo.len() == %0d, should be 14", foo.len());
error_count = error_count+1;
end
if (error_count == 0) $display("PASSED");
end
endmodule // main

View File

@ -0,0 +1,46 @@
module main;
string foo;
int error_count;
task check_char(input int idx, input [7:0] val);
if (foo[idx] !== val) begin
$display("FAILED: foo[%0d]==%02h, expecting %02h",
idx, foo[idx], val);
error_count = error_count+1;
end
endtask // check_char
initial begin
// These are the special charasters in strings as defined by
// IEEE Std 1800-2017: 5.9.1 Special characters in strings.
// The string assignment is governed by:
// IEEE Std 1800-2017: 6.16 String data type
foo = "abc";
foo = {foo, "\n\t\\\"\v\f\a\001\002\x03\x04"};
error_count = 0;
check_char(0, 8'h61); // 'a'
check_char(1, 8'h62); // 'b'
check_char(2, 8'h63); // 'c'
check_char(3, 8'h0a); // '\n'
check_char(4, 8'h09); // '\t'
check_char(5, 8'h5c); // '\\'
check_char(6, 8'h22); // '\"'
check_char(7, 8'h0b); // '\v'
check_char(8, 8'h0c); // '\f'
check_char(9, 8'h07); // '\a'
check_char(10, 8'h01); // '\001'
check_char(11, 8'h02); // '\002'
check_char(12, 8'h03); // '\x03'
check_char(13, 8'h04); // '\x04'
if (foo.len() !== 14) begin
$display("FAILED: foo.len() == %0d, should be 14", foo.len());
error_count = error_count+1;
end
if (error_count == 0) $display("PASSED");
end
endmodule // main

View File

@ -531,6 +531,8 @@ sv_string3 normal,-g2009 ivltests
sv_string4 normal,-g2009 ivltests
sv_string5 normal,-g2009 ivltests
sv_string6 normal,-g2009 ivltests
sv_string7 normal,-g2009 ivltests
sv_string7b normal,-g2009 ivltests
sv_timeunit_prec1 normal,-g2005-sv ivltests
sv_timeunit_prec2 normal,-g2009 ivltests
sv_timeunit_prec3a normal,-g2005-sv ivltests gold=sv_timeunit_prec3a.gold

View File

@ -81,6 +81,18 @@ static string process_verilog_string_quotes(const string&str)
res = res + '\t';
idx += 1;
break;
case 'v':
res = res + '\v';
idx += 1;
break;
case 'f':
res = res + '\f';
idx += 1;
break;
case 'a':
res = res + '\a';
idx += 1;
break;
case '0':
case '1':
case '2':
@ -101,6 +113,27 @@ static string process_verilog_string_quotes(const string&str)
res = res + byte_val;
break;
}
case 'x': {
char byte_val = 0;
int odx = 1;
while (odx < 3 && idx+odx < str_len) {
if (str[idx+odx] >= '0' && str[idx+odx] <= '9') {
byte_val = 16*byte_val + str[idx+odx]-'0';
odx += 1;
} else if (str[idx+odx] >= 'a' && str[idx+odx] <= 'f') {
byte_val = 16*byte_val + str[idx+odx]-'a'+10;
odx += 1;
} else if (str[idx+odx] >= 'A' && str[idx+odx] <= 'F') {
byte_val = 16*byte_val + str[idx+odx]-'A'+10;
odx += 1;
} else {
break;
}
}
idx += odx;
res = res + byte_val;
break;
}
default:
res = res + str[idx];
idx += 1;

View File

@ -364,6 +364,56 @@ void vthread_s::debug_dump(ostream&fd, const char*label)
fd << "**** Done ****" << endl;
}
/*
* This function converts the text format of the string by interpreting
* any octal characters (\nnn) to their single byte value. We do this here
* because the text value in the vvp_code_t is stored as a C string. This
* converts it to a C++ string that can hold binary values. We only have
* to handle the octal escapes because the main compiler takes care of all
* the other string special characters and normalizes the strings to use
* only this format.
*/
static string filter_string(const char*text)
{
vector<char> tmp (strlen(text)+1);
size_t dst = 0;
for (const char*ptr = text ; *ptr ; ptr += 1) {
// Not an escape? Move on.
if (*ptr != '\\') {
tmp[dst++] = *ptr;
continue;
}
// Now we know that *ptr is pointing to a \ character and we
// have an octal sequence coming up. Advance the ptr and start
// processing octal digits.
ptr += 1;
if (*ptr == 0)
break;
char byte = 0;
int cnt = 3;
while (*ptr && cnt > 0 && *ptr >= '0' && *ptr <= '7') {
byte *= 8;
byte += *ptr - '0';
cnt -= 1;
ptr += 1;
}
tmp[dst++] = byte;
// After the while loop above, the ptr points to the next character,
// but the for-loop condition is assuming that ptr points to the last
// character, since it has the ptr+=1.
ptr -= 1;
}
// Put a nul byte at the end of the built up string, but really we are
// using the known length in the string constructor.
tmp[dst] = 0;
string res (&tmp[0], dst);
return res;
}
static void do_join(vthread_t thr, vthread_t child);
__vpiScope* vthread_scope(struct vthread_s*thr)
@ -2264,7 +2314,7 @@ bool of_CONCAT_STR(vthread_t thr, vvp_code_t)
bool of_CONCATI_STR(vthread_t thr, vvp_code_t cp)
{
const char*text = cp->text;
thr->peek_str(0).append(text);
thr->peek_str(0).append(filter_string(text));
return true;
}
@ -5012,7 +5062,7 @@ bool of_PUSHI_REAL(vthread_t thr, vvp_code_t cp)
bool of_PUSHI_STR(vthread_t thr, vvp_code_t cp)
{
const char*text = cp->text;
thr->push_str(string(text));
thr->push_str(filter_string(text));
return true;
}