Support string.toupper and string.tolower.

This commit is contained in:
Wilson Snyder 2019-11-17 05:05:09 -05:00
parent d480c2f033
commit 0c0198cf55
8 changed files with 116 additions and 9 deletions

View File

@ -6,6 +6,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
*** Add +verilator+error+limit to see more assertion errors. [Peter Monsson]
*** Support string.toupper and string.tolower.
*** Support $rewind and $ungetc.
**** Add -Wpedantic for compliance testing.

View File

@ -1754,7 +1754,22 @@ const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE {
}
//===========================================================================
// Heavy functions
// Heavy string functions
std::string VL_TOLOWER_NN(const std::string& ld) VL_MT_SAFE {
std::string out = ld;
for (std::string::iterator it = out.begin(); it != out.end(); ++it) {
*it = tolower(*it);
}
return out;
}
std::string VL_TOUPPER_NN(const std::string& ld) VL_MT_SAFE {
std::string out = ld;
for (std::string::iterator it = out.begin(); it != out.end(); ++it) {
*it = toupper(*it);
}
return out;
}
std::string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp) VL_MT_SAFE {
// See also _VL_VINT_TO_STRING

View File

@ -61,6 +61,8 @@ inline std::string VL_REPLICATEN_NNI(int obits,int lbits,int rbits,
}
inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); }
extern std::string VL_TOLOWER_NN(const std::string& ld);
extern std::string VL_TOUPPER_NN(const std::string& ld);
extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE;
extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb,

View File

@ -4532,6 +4532,32 @@ public:
virtual string emitVerilog() { return "%f$atanh(%l)"; }
virtual string emitC() { return "atanh(%li)"; }
};
class AstToLowerN : public AstNodeUniop {
// string.tolower()
public:
AstToLowerN(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
dtypeSetString(); }
ASTNODE_NODE_FUNCS(ToLowerN)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opToLowerN(lhs); }
virtual string emitVerilog() { return "%l.tolower()"; }
virtual string emitC() { return "VL_TOLOWER_NN(%li)"; }
virtual bool cleanOut() const { return true; }
virtual bool cleanLhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
};
class AstToUpperN : public AstNodeUniop {
// string.toupper()
public:
AstToUpperN(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
dtypeSetString(); }
ASTNODE_NODE_FUNCS(ToUpperN)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opToUpperN(lhs); }
virtual string emitVerilog() { return "%l.toupper()"; }
virtual string emitC() { return "VL_TOUPPER_NN(%li)"; }
virtual bool cleanOut() const { return true; }
virtual bool cleanLhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
};
//======================================================================
// Binary ops

View File

@ -2074,6 +2074,25 @@ V3Number& V3Number::opReplN(const V3Number& lhs, uint32_t rhsval) {
}
return setString(out);
}
V3Number& V3Number::opToLowerN(const V3Number& lhs) {
NUM_ASSERT_OP_ARGS1(lhs);
NUM_ASSERT_STRING_ARGS1(lhs);
std::string out = lhs.toString();
for (std::string::iterator it = out.begin(); it != out.end(); ++it) {
*it = tolower(*it);
}
return setString(out);
}
V3Number& V3Number::opToUpperN(const V3Number& lhs) {
NUM_ASSERT_OP_ARGS1(lhs);
NUM_ASSERT_STRING_ARGS1(lhs);
std::string out = lhs.toString();
for (std::string::iterator it = out.begin(); it != out.end(); ++it) {
*it = toupper(*it);
}
return setString(out);
}
V3Number& V3Number::opEqN(const V3Number& lhs, const V3Number& rhs) {
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_STRING_ARGS2(lhs, rhs);

View File

@ -288,6 +288,8 @@ public:
V3Number& opSel (const V3Number& lhs, uint32_t msbval, uint32_t lsbval);
V3Number& opSelInto (const V3Number& lhs, const V3Number& lsb, int width);
V3Number& opSelInto (const V3Number& lhs, int lsbval, int width);
V3Number& opToLowerN(const V3Number& lhs);
V3Number& opToUpperN(const V3Number& lhs);
V3Number& opCond (const V3Number& lhs, const V3Number& if1s, const V3Number& if0s);
V3Number& opCaseEq (const V3Number& lhs, const V3Number& rhs);
V3Number& opCaseNeq (const V3Number& lhs, const V3Number& rhs);

View File

@ -442,6 +442,18 @@ private:
}
}
}
virtual void visit(AstToLowerN* nodep) {
if (m_vup->prelim()) {
iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
nodep->dtypeSetString();
}
}
virtual void visit(AstToUpperN* nodep) {
if (m_vup->prelim()) {
iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
nodep->dtypeSetString();
}
}
virtual void visit(AstReplicate* nodep) {
// IEEE-2012 Table 11-21:
// LHS, RHS is self-determined
@ -1804,8 +1816,26 @@ private:
} else if (nodep->name() == "realtoa") {
methodOkArguments(nodep, 1, 1);
replaceWithSFormat(nodep, "%g"); VL_DANGLING(nodep);
} else {
} else if (nodep->name() == "tolower") {
methodOkArguments(nodep, 0, 0);
AstNode* newp = new AstToLowerN(nodep->fileline(), nodep->fromp()->unlinkFrBack());
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
} else if (nodep->name() == "toupper") {
methodOkArguments(nodep, 0, 0);
AstNode* newp = new AstToUpperN(nodep->fileline(), nodep->fromp()->unlinkFrBack());
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
} else if (nodep->name() == "atobin"
|| nodep->name() == "atohex"
|| nodep->name() == "atoi"
|| nodep->name() == "atooct"
|| nodep->name() == "atoreal"
|| nodep->name() == "compare"
|| nodep->name() == "icompare"
|| nodep->name() == "getc"
|| nodep->name() == "putc") {
nodep->v3error("Unsupported: built-in string method "<<nodep->prettyNameQ());
} else {
nodep->v3error("Unknown built-in string method "<<nodep->prettyNameQ());
}
}

View File

@ -20,11 +20,11 @@ module t (/*AUTOARG*/
// Check constification
initial begin
s="1234"; `checkh(s.len(),4);
s="ab7CD"; `checks(s.toupper(), "AB7CD");
s="ab7CD"; `checks(s.tolower(), "ab7cd");
`ifndef VERILATOR
s="1234"; s.putc(2, "z"); `checks(s, "12z4");
s="1234"; `checkh(s.getc(2), "3");
s="abCD"; `checks(s.toupper(), "ABCD");
s="abCD"; `checks(s.tolower(), "abcd");
s="b"; if (s.compare("a") <= 0) $stop;
s="b"; if (s.compare("b") != 0) $stop;
s="b"; if (s.compare("c") >= 0) $stop;
@ -42,6 +42,9 @@ module t (/*AUTOARG*/
s.octtoa(123); `checks(s, "173");
s.bintoa(123); `checks(s, "1111011");
s.realtoa(1.23); `checks(s, "1.23");
s = "bAr";
s = s.toupper; `checks(s, "BAR");
s = s.tolower; `checks(s, "bar");
end
// Check runtime
@ -54,40 +57,48 @@ module t (/*AUTOARG*/
else if (cyc==1) begin
`checkh(s.len(),4);
end
`ifndef VERILATOR
else if (cyc==2) begin
`ifndef VERILATOR
s.putc(2, "z");
`endif
end
else if (cyc==3) begin
`ifndef VERILATOR
`checks(s, "12z4");
`checkh(s.getc(2), "z");
s="abCD";
`endif
s="ab3CD";
end
else if (cyc==4) begin
`checks(s.toupper(), "ABCD");
`checks(s.tolower(), "abcd");
`checks(s.toupper(), "AB3CD");
`checks(s.tolower(), "ab3cd");
s="b";
end
else if (cyc==5) begin
`ifndef VERILATOR
if (s.compare("a") <= 0) $stop;
if (s.compare("b") != 0) $stop;
if (s.compare("c") >= 0) $stop;
if (s.icompare("A") < 0) $stop;
if (s.icompare("B") != 0) $stop;
if (s.icompare("C") >= 0) $stop;
`endif
s="101";
end
else if (cyc==7) begin
`ifndef VERILATOR
`checkh(s.atoi(), 'd101);
`checkh(s.atohex(), 'h101);
`checkh(s.atooct(), 'o101);
`checkh(s.atobin(), 'b101);
`endif
s="1.23";
end
else if (cyc==8) begin
`ifndef VERILATOR
`checkg(s.atoreal(), 1.23);
end
`endif
end
else if (cyc==9) begin
s.itoa(123);
end