mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
icode assembler changes
This commit is contained in:
parent
42308db283
commit
169089589e
@ -15,7 +15,9 @@ objs = hash.o \
|
||||
vmtypes.o \
|
||||
debugger.o
|
||||
|
||||
test_objs = hash.o \
|
||||
test_objs = hash.o \
|
||||
icodeasm.o \
|
||||
ica_test.o \
|
||||
icodegenerator.o \
|
||||
interpreter.o \
|
||||
jsmath.o \
|
||||
@ -44,8 +46,8 @@ gc.a:
|
||||
gctest: gc_allocator.o
|
||||
$(CC) -o $@ -ggdb $^ $(libs)
|
||||
|
||||
ica_test:
|
||||
$(CC) $(CFLAGS) -o ica_test ica_test.cpp icodeasm.cpp $(test_objs) $(libs)
|
||||
ica_test: $(test_objs)
|
||||
$(CC) $(CFLAGS) -o $@ $(test_objs) $(libs)
|
||||
|
||||
clean:
|
||||
rm -f $(objs)
|
||||
|
@ -36,36 +36,108 @@
|
||||
|
||||
#include "icodeasm.h"
|
||||
|
||||
void testAlpha (JavaScript::ICodeASM::ICodeParser icp, const string &str,
|
||||
const string &expect)
|
||||
{
|
||||
string *result;
|
||||
icp.ParseAlpha (str.begin(), str.end(), &result);
|
||||
if (*result == expect)
|
||||
fprintf (stderr, "PASS: ");
|
||||
else
|
||||
fprintf (stderr, "FAIL: ");
|
||||
fprintf (stderr, "string '%s' alpha parsed as '%s'\n", str.c_str(),
|
||||
result->c_str());
|
||||
}
|
||||
|
||||
void testBool (JavaScript::ICodeASM::ICodeParser &icp, const string &str,
|
||||
bool expect)
|
||||
{
|
||||
bool b;
|
||||
icp.ParseBool (str.begin(), str.end(), &b);
|
||||
if (b == expect)
|
||||
fprintf (stderr, "PASS: ");
|
||||
else
|
||||
fprintf (stderr, "FAIL: ");
|
||||
fprintf (stderr, "string '%s' bool parsed as %i\n", str.c_str(), b);
|
||||
}
|
||||
|
||||
void testDouble (JavaScript::ICodeASM::ICodeParser icp, const string &str,
|
||||
double expect)
|
||||
{
|
||||
double result;
|
||||
icp.ParseDouble (str.begin(), str.end(), &result);
|
||||
if (result == expect)
|
||||
fprintf (stderr, "PASS: ");
|
||||
else
|
||||
fprintf (stderr, "FAIL: ");
|
||||
fprintf (stderr, "string '%s' double parsed as %f\n", str.c_str(),
|
||||
result);
|
||||
}
|
||||
|
||||
void testString (JavaScript::ICodeASM::ICodeParser icp, const string &str,
|
||||
const string &expect)
|
||||
{
|
||||
string *result;
|
||||
icp.ParseString (str.begin(), str.end(), &result);
|
||||
if (*result == expect)
|
||||
fprintf (stderr, "PASS: ");
|
||||
else
|
||||
fprintf (stderr, "FAIL: ");
|
||||
fprintf (stderr, "string '%s' string parsed as '%s'\n", str.c_str(),
|
||||
result->c_str());
|
||||
}
|
||||
|
||||
void testUInt32 (JavaScript::ICodeASM::ICodeParser icp, const string &str,
|
||||
uint32 expect)
|
||||
{
|
||||
uint32 result;
|
||||
icp.ParseUInt32 (str.begin(), str.end(), &result);
|
||||
if (result == expect)
|
||||
fprintf (stderr, "PASS: ");
|
||||
else
|
||||
fprintf (stderr, "FAIL: ");
|
||||
fprintf (stderr, "string '%s' uint32 parsed as %u\n", str.c_str(),
|
||||
result);
|
||||
}
|
||||
|
||||
int
|
||||
main (int , char **)
|
||||
{
|
||||
JavaScript::ICodeASM::ICodeParser icp;
|
||||
bool b;
|
||||
string str;
|
||||
|
||||
#define BOOL_TEST(s, expect) \
|
||||
{ \
|
||||
b = false; \
|
||||
str = s; \
|
||||
icp.ParseBool (str.begin(), str.end(), &b); \
|
||||
if (b == expect) \
|
||||
fprintf (stderr, "PASS: "); \
|
||||
else \
|
||||
fprintf (stderr, "FAIL: "); \
|
||||
fprintf (stderr, "string %s bool parsed as %i\n", str.c_str(), b); \
|
||||
} \
|
||||
testAlpha (icp, "False", "False");
|
||||
testAlpha (icp, "fe fi fo fum", "fe");
|
||||
testAlpha (icp, " bla", "");
|
||||
|
||||
BOOL_TEST ("true", true);
|
||||
BOOL_TEST ("True", true);
|
||||
BOOL_TEST ("tRue", true);
|
||||
BOOL_TEST ("TRUE", true);
|
||||
BOOL_TEST ("True", true);
|
||||
BOOL_TEST ("false", false);
|
||||
BOOL_TEST ("False", false);
|
||||
BOOL_TEST ("fAlSe", false);
|
||||
BOOL_TEST ("FALSE", false);
|
||||
BOOL_TEST ("False", false);
|
||||
testBool (icp, "true", true);
|
||||
testBool (icp, "True", true);
|
||||
testBool (icp, "tRue", true);
|
||||
testBool (icp, "TRUE", true);
|
||||
testBool (icp, "True", true);
|
||||
testBool (icp, "false", false);
|
||||
testBool (icp, "False", false);
|
||||
testBool (icp, "fAlSe", false);
|
||||
testBool (icp, "FALSE", false);
|
||||
testBool (icp, "False", false);
|
||||
|
||||
testDouble (icp, "123", 123);
|
||||
testDouble (icp, "12.3", 12.3);
|
||||
testDouble (icp, "-123", -123);
|
||||
testDouble (icp, "-12.3", -12.3);
|
||||
|
||||
testString (icp, "\"fe fi fo fum\"", "fe fi fo fum");
|
||||
testString (icp, "'the tab is ->\\t<- here'", "the tab is ->\t<- here");
|
||||
testString (icp, "'the newline is ->\\n<- here'", "the newline is ->\n<- here");
|
||||
testString (icp, "'the cr is ->\\r<- here'", "the cr is ->\r<- here");
|
||||
testString (icp, "\"an \\\"escaped\\\" string\"", "an \"escaped\" string");
|
||||
|
||||
testUInt32 (icp, "123", 123);
|
||||
testUInt32 (icp, "12.3", 12);
|
||||
testUInt32 (icp, "-123", 0);
|
||||
testUInt32 (icp, "-12.3", 0);
|
||||
/* XXX what to do with the overflow? */
|
||||
//testUInt32 (icp, "12123687213612873621873438754387934657834", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,8 @@
|
||||
|
||||
namespace JavaScript {
|
||||
namespace ICodeASM {
|
||||
|
||||
static char *keyword_offset = "offset";
|
||||
|
||||
int cmp_nocase (const string& s1, string::const_iterator s2_begin,
|
||||
string::const_iterator s2_end)
|
||||
{
|
||||
@ -102,11 +103,21 @@ namespace ICodeASM {
|
||||
tl.begin = curpos;
|
||||
return tl;
|
||||
|
||||
case '-':
|
||||
tl.estimate = teMinus;
|
||||
tl.begin = curpos;
|
||||
return tl;
|
||||
|
||||
case '+':
|
||||
tl.estimate = tePlus;
|
||||
tl.begin = curpos;
|
||||
return tl;
|
||||
|
||||
case ',':
|
||||
tl.estimate = teComma;
|
||||
tl.begin = curpos;
|
||||
return tl;
|
||||
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
tl.estimate = teString;
|
||||
@ -131,7 +142,7 @@ namespace ICodeASM {
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseAlpha (iter begin, iter end, string *rval)
|
||||
ICodeParser::ParseAlpha (iter begin, iter end, string **rval)
|
||||
{
|
||||
iter curpos;
|
||||
string *str = new string();
|
||||
@ -152,7 +163,7 @@ namespace ICodeASM {
|
||||
}
|
||||
scan_done:
|
||||
|
||||
rval = str;
|
||||
*rval = str;
|
||||
return curpos;
|
||||
}
|
||||
|
||||
@ -187,16 +198,31 @@ namespace ICodeASM {
|
||||
ICodeParser::ParseDouble (iter begin, iter end, double *rval)
|
||||
{
|
||||
/* XXX add overflow checking */
|
||||
*rval = 0;
|
||||
uint32 integer;
|
||||
int sign = 1;
|
||||
|
||||
/* pay no attention to the assignment of sign in the test condition :O */
|
||||
if (*begin == '+' || (*begin == '-' && (sign = -1)) {
|
||||
TokenLocation tl = SeekTokenStart (++begin, end);
|
||||
if (tl.estimate != teNumeric)
|
||||
throw new ICodeParseException ("Expected double value");
|
||||
begin = tl.begin;
|
||||
}
|
||||
|
||||
|
||||
iter curpos = ParseUInt32 (begin, end, &integer);
|
||||
*rval = static_cast<double>(integer);
|
||||
if (*curpos != '.')
|
||||
{
|
||||
*rval *= sign;
|
||||
return curpos;
|
||||
}
|
||||
|
||||
++curpos;
|
||||
uint32 position = 0;
|
||||
int32 position = 0;
|
||||
|
||||
for (curpos = begin; curpos < end; ++curpos) {
|
||||
for (; curpos < end; ++curpos) {
|
||||
switch (*curpos)
|
||||
{
|
||||
case '0'...'9':
|
||||
@ -209,19 +235,44 @@ namespace ICodeASM {
|
||||
}
|
||||
scan_done:
|
||||
|
||||
*rval *= sign;
|
||||
|
||||
return curpos;
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseString (iter begin, iter end, string *rval)
|
||||
ICodeParser::ParseInt32 (iter begin, iter end, int32 *rval)
|
||||
{
|
||||
*rval = 0;
|
||||
int sign = 1;
|
||||
|
||||
/* pay no attention to the assignment of sign in the test condition :O */
|
||||
if ((*begin == '+') || (*begin == '-' && (sign = -1))) {
|
||||
TokenLocation tl = SeekTokenStart (++begin, end);
|
||||
if (tl.estimate != teNumeric)
|
||||
throw new ICodeParseException ("Expected int32 value");
|
||||
begin = tl.begin;
|
||||
}
|
||||
|
||||
end = ParseUInt32 (begin, end, rval);
|
||||
|
||||
*rval *= sign;
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseString (iter begin, iter end, string **rval)
|
||||
{
|
||||
char delim = *begin;
|
||||
bool isTerminated = false;
|
||||
/* XXX not exactly exception safe, string may never get deleted */
|
||||
string *str = new string();
|
||||
*rval = 0;
|
||||
|
||||
if (delim != '\'' && delim != '"') {
|
||||
ASSERT ("|begin| does not point at a string");
|
||||
delete str;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -303,7 +354,7 @@ namespace ICodeASM {
|
||||
throw new ICodeParseException ("Unterminated string literal.");
|
||||
}
|
||||
|
||||
rval = str;
|
||||
*rval = str;
|
||||
return curpos;
|
||||
}
|
||||
|
||||
@ -311,7 +362,8 @@ namespace ICodeASM {
|
||||
ICodeParser::ParseUInt32 (iter begin, iter end, uint32 *rval)
|
||||
{
|
||||
/* XXX add overflow checking */
|
||||
int32 position = 0;
|
||||
*rval = 0;
|
||||
int32 position = -1;
|
||||
iter curpos;
|
||||
|
||||
for (curpos = begin; curpos < end; ++curpos) {
|
||||
@ -334,11 +386,17 @@ namespace ICodeASM {
|
||||
return curpos;
|
||||
}
|
||||
|
||||
iter ICodeParser::ParseInstruction (uint icodeID, iter start, iter end)
|
||||
iter ICodeParser::ParseInstruction (uint icodeID, iter begin, iter end)
|
||||
{
|
||||
iter curpos = start;
|
||||
iter curpos = begin;
|
||||
StatementNode *node = new StatementNode();
|
||||
node->begin = begin;
|
||||
node->icodeID = icodeID;
|
||||
|
||||
/* add the node now, so the parse*operand functions can see it (to add
|
||||
* it to the fixup vector, for example.)
|
||||
*/
|
||||
mStatementNodes.push_back (node);
|
||||
|
||||
# define CASE_TYPE(T) \
|
||||
case ot##T: \
|
||||
@ -370,7 +428,7 @@ namespace ICodeASM {
|
||||
}
|
||||
|
||||
# undef CASE_TYPE
|
||||
|
||||
|
||||
return curpos;
|
||||
}
|
||||
|
||||
@ -444,7 +502,7 @@ namespace ICodeASM {
|
||||
if (tl.estimate != teString)
|
||||
throw new ICodeParseException ("Expected BinaryOp as a quoted string.");
|
||||
string *str;
|
||||
end = ParseString (tl.begin, end, str);
|
||||
end = ParseString (tl.begin, end, &str);
|
||||
o->asString = str;
|
||||
return end;
|
||||
}
|
||||
@ -461,11 +519,15 @@ namespace ICodeASM {
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseDoubleOperand (iter begin, iter /*end*/,
|
||||
AnyOperand */*o*/)
|
||||
ICodeParser::ParseDoubleOperand (iter begin, iter end, AnyOperand *o)
|
||||
{
|
||||
ASSERT ("Not Implemented.");
|
||||
return begin;
|
||||
TokenLocation tl = SeekTokenStart (begin, end);
|
||||
|
||||
if ((tl.estimate != teNumeric) && (tl.estimate != teMinus) &&
|
||||
(tl.estimate != tePlus))
|
||||
throw new ICodeParseException ("Expected double value.");
|
||||
|
||||
return ParseDouble (tl.begin, end, &o->asDouble);
|
||||
}
|
||||
|
||||
iter
|
||||
@ -477,49 +539,101 @@ namespace ICodeASM {
|
||||
throw new ICodeParseException ("Expected ICode Module as a quoted string.");
|
||||
|
||||
string *str;
|
||||
end = ParseString (tl.begin, end, str);
|
||||
end = ParseString (tl.begin, end, &str);
|
||||
o->asString = str;
|
||||
return end;
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseJSClassOperand (iter begin, iter /*end*/,
|
||||
AnyOperand */*o*/)
|
||||
ICodeParser::ParseJSClassOperand (iter begin, iter end, AnyOperand *o)
|
||||
{
|
||||
ASSERT ("Not Implemented.");
|
||||
return begin;
|
||||
TokenLocation tl = SeekTokenStart (begin, end);
|
||||
|
||||
if (tl.estimate != teString)
|
||||
throw new ICodeParseException ("Expected JSClass as a quoted string.");
|
||||
|
||||
string *str;
|
||||
end = ParseString (tl.begin, end, &str);
|
||||
o->asString = str;
|
||||
return end;
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseJSStringOperand (iter begin, iter /*end*/,
|
||||
AnyOperand */*o*/)
|
||||
ICodeParser::ParseJSStringOperand (iter begin, iter end, AnyOperand *o)
|
||||
{
|
||||
ASSERT ("Not Implemented.");
|
||||
return begin;
|
||||
TokenLocation tl = SeekTokenStart (begin, end);
|
||||
|
||||
if (tl.estimate != teString)
|
||||
throw new ICodeParseException ("Expected JSString as a quoted string.");
|
||||
|
||||
string *str;
|
||||
end = ParseString (tl.begin, end, &str);
|
||||
o->asString = str;
|
||||
return end;
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseJSFunctionOperand (iter begin, iter /*end*/,
|
||||
AnyOperand */*o*/)
|
||||
ICodeParser::ParseJSFunctionOperand (iter begin, iter end, AnyOperand *o)
|
||||
{
|
||||
ASSERT ("Not Implemented.");
|
||||
return begin;
|
||||
TokenLocation tl = SeekTokenStart (begin, end);
|
||||
|
||||
if (tl.estimate != teString)
|
||||
throw new ICodeParseException ("Expected JSFunction as a quoted string.");
|
||||
|
||||
string *str;
|
||||
end = ParseString (tl.begin, end, &str);
|
||||
o->asString = str;
|
||||
return end;
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseJSTypeOperand (iter begin, iter /*end*/,
|
||||
AnyOperand */*o*/)
|
||||
ICodeParser::ParseJSTypeOperand (iter begin, iter end, AnyOperand *o)
|
||||
{
|
||||
ASSERT ("Not Implemented.");
|
||||
return begin;
|
||||
TokenLocation tl = SeekTokenStart (begin, end);
|
||||
|
||||
if (tl.estimate != teString)
|
||||
throw new ICodeParseException ("Expected JSType as a quoted string.");
|
||||
string *str;
|
||||
end = ParseString (tl.begin, end, &str);
|
||||
o->asString = str;
|
||||
return end;
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseLabelOperand (iter begin, iter /*end*/,
|
||||
AnyOperand */*o*/)
|
||||
ICodeParser::ParseLabelOperand (iter begin, iter end, AnyOperand *o)
|
||||
{
|
||||
ASSERT ("Not Implemented.");
|
||||
return begin;
|
||||
TokenLocation tl = SeekTokenStart (begin, end);
|
||||
|
||||
if (tl.estimate != teAlpha)
|
||||
throw new ICodeParseException ("Expected Label Identifier or Offset keyword.");
|
||||
|
||||
string *str;
|
||||
begin = ParseAlpha (tl.begin, end, &str);
|
||||
|
||||
if (cmp_nocase(*string, keyword_offset, keyword_offset +
|
||||
strlen(keyword_offset) + 1) == 0) {
|
||||
/* label expressed as "Offset +/-N" */
|
||||
tl = SeekTokenStart (begin, end);
|
||||
|
||||
if ((tl.estimate != teNumeric) && (tl.estimate != teMinus) &&
|
||||
(tl.estimate != tePlus))
|
||||
throw new ICodeParseException ("Expected numeric value after Offset keyword.");
|
||||
|
||||
begin = ParseInt32 (tl.begin, end, &(o->asInt32));
|
||||
return begin;
|
||||
} else {
|
||||
/* label expressed as "label_name" */
|
||||
LabelMap::const_iterator l = mLabels.find(str->c_string());
|
||||
if (l == mLabels.end())
|
||||
{
|
||||
/* if we can't find the label, mark it as a fixup for later */
|
||||
o->asString = str;
|
||||
mFixupNodes.push_back (mStatementNodes.back());
|
||||
return begin;
|
||||
}
|
||||
/* XXX continue here... */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
iter
|
||||
|
@ -46,7 +46,9 @@ namespace ICodeASM {
|
||||
teUnknown,
|
||||
teIllegal,
|
||||
teComma,
|
||||
teMinus,
|
||||
teNumeric,
|
||||
tePlus,
|
||||
teAlpha,
|
||||
teString,
|
||||
teNotARegister
|
||||
@ -84,6 +86,7 @@ namespace ICodeASM {
|
||||
/* eww */
|
||||
double asDouble;
|
||||
uint32 asUInt32;
|
||||
int32 asInt32;
|
||||
VM::Register asRegister;
|
||||
bool asBoolean;
|
||||
VM::ArgumentList *asArgumentList;
|
||||
@ -91,6 +94,7 @@ namespace ICodeASM {
|
||||
};
|
||||
|
||||
struct StatementNode {
|
||||
iter pos;
|
||||
uint icodeID;
|
||||
AnyOperand operand[3];
|
||||
};
|
||||
@ -100,7 +104,9 @@ namespace ICodeASM {
|
||||
private:
|
||||
uint mMaxRegister;
|
||||
std::vector<StatementNode *> mStatementNodes;
|
||||
std::map<string, StatementNode **> mLabels;
|
||||
std::vector<StatementNode *> mFixupNodes;
|
||||
typedef std::map<const char *, StatementNode **> LabelMap;
|
||||
LabelMap mLabels;
|
||||
|
||||
public:
|
||||
void ParseSourceFromString (const string source);
|
||||
@ -108,12 +114,17 @@ namespace ICodeASM {
|
||||
/* locate the beginning of the next token, and guess what it might be */
|
||||
TokenLocation SeekTokenStart (iter begin, iter end);
|
||||
|
||||
/* general purpose parse functions */
|
||||
iter ParseAlpha (iter begin, iter end, string *rval);
|
||||
/* general purpose parse functions; |begin| is expected to point
|
||||
* at the start of the token to be processed (eg, these routines
|
||||
* don't call |SeekTokenStart|, and (currently, this might change) no
|
||||
* initial check is done to ensure that |begin| != |end|.
|
||||
*/
|
||||
iter ParseAlpha (iter begin, iter end, string **rval);
|
||||
iter ParseBool (iter begin, iter end, bool *rval);
|
||||
iter ParseDouble (iter begin, iter end, double *rval);
|
||||
iter ParseString (iter begin, iter end, string *rval);
|
||||
iter ParseUInt32 (iter begin, iter end, uint32 *rval);
|
||||
iter ParseDouble (iter begin, iter end, double *rval);
|
||||
iter ParseInt32 (iter begin, iter end, uint32 *rval);
|
||||
iter ParseString (iter begin, iter end, string **rval);
|
||||
iter ParseUInt32 (iter begin, iter end, uint32 *rval);
|
||||
|
||||
/* "high level" parse functions */
|
||||
iter ParseInstruction (uint icodeID, iter start, iter end);
|
||||
|
@ -15,7 +15,9 @@ objs = hash.o \
|
||||
vmtypes.o \
|
||||
debugger.o
|
||||
|
||||
test_objs = hash.o \
|
||||
test_objs = hash.o \
|
||||
icodeasm.o \
|
||||
ica_test.o \
|
||||
icodegenerator.o \
|
||||
interpreter.o \
|
||||
jsmath.o \
|
||||
@ -44,8 +46,8 @@ gc.a:
|
||||
gctest: gc_allocator.o
|
||||
$(CC) -o $@ -ggdb $^ $(libs)
|
||||
|
||||
ica_test:
|
||||
$(CC) $(CFLAGS) -o ica_test ica_test.cpp icodeasm.cpp $(test_objs) $(libs)
|
||||
ica_test: $(test_objs)
|
||||
$(CC) $(CFLAGS) -o $@ $(test_objs) $(libs)
|
||||
|
||||
clean:
|
||||
rm -f $(objs)
|
||||
|
@ -36,36 +36,108 @@
|
||||
|
||||
#include "icodeasm.h"
|
||||
|
||||
void testAlpha (JavaScript::ICodeASM::ICodeParser icp, const string &str,
|
||||
const string &expect)
|
||||
{
|
||||
string *result;
|
||||
icp.ParseAlpha (str.begin(), str.end(), &result);
|
||||
if (*result == expect)
|
||||
fprintf (stderr, "PASS: ");
|
||||
else
|
||||
fprintf (stderr, "FAIL: ");
|
||||
fprintf (stderr, "string '%s' alpha parsed as '%s'\n", str.c_str(),
|
||||
result->c_str());
|
||||
}
|
||||
|
||||
void testBool (JavaScript::ICodeASM::ICodeParser &icp, const string &str,
|
||||
bool expect)
|
||||
{
|
||||
bool b;
|
||||
icp.ParseBool (str.begin(), str.end(), &b);
|
||||
if (b == expect)
|
||||
fprintf (stderr, "PASS: ");
|
||||
else
|
||||
fprintf (stderr, "FAIL: ");
|
||||
fprintf (stderr, "string '%s' bool parsed as %i\n", str.c_str(), b);
|
||||
}
|
||||
|
||||
void testDouble (JavaScript::ICodeASM::ICodeParser icp, const string &str,
|
||||
double expect)
|
||||
{
|
||||
double result;
|
||||
icp.ParseDouble (str.begin(), str.end(), &result);
|
||||
if (result == expect)
|
||||
fprintf (stderr, "PASS: ");
|
||||
else
|
||||
fprintf (stderr, "FAIL: ");
|
||||
fprintf (stderr, "string '%s' double parsed as %f\n", str.c_str(),
|
||||
result);
|
||||
}
|
||||
|
||||
void testString (JavaScript::ICodeASM::ICodeParser icp, const string &str,
|
||||
const string &expect)
|
||||
{
|
||||
string *result;
|
||||
icp.ParseString (str.begin(), str.end(), &result);
|
||||
if (*result == expect)
|
||||
fprintf (stderr, "PASS: ");
|
||||
else
|
||||
fprintf (stderr, "FAIL: ");
|
||||
fprintf (stderr, "string '%s' string parsed as '%s'\n", str.c_str(),
|
||||
result->c_str());
|
||||
}
|
||||
|
||||
void testUInt32 (JavaScript::ICodeASM::ICodeParser icp, const string &str,
|
||||
uint32 expect)
|
||||
{
|
||||
uint32 result;
|
||||
icp.ParseUInt32 (str.begin(), str.end(), &result);
|
||||
if (result == expect)
|
||||
fprintf (stderr, "PASS: ");
|
||||
else
|
||||
fprintf (stderr, "FAIL: ");
|
||||
fprintf (stderr, "string '%s' uint32 parsed as %u\n", str.c_str(),
|
||||
result);
|
||||
}
|
||||
|
||||
int
|
||||
main (int , char **)
|
||||
{
|
||||
JavaScript::ICodeASM::ICodeParser icp;
|
||||
bool b;
|
||||
string str;
|
||||
|
||||
#define BOOL_TEST(s, expect) \
|
||||
{ \
|
||||
b = false; \
|
||||
str = s; \
|
||||
icp.ParseBool (str.begin(), str.end(), &b); \
|
||||
if (b == expect) \
|
||||
fprintf (stderr, "PASS: "); \
|
||||
else \
|
||||
fprintf (stderr, "FAIL: "); \
|
||||
fprintf (stderr, "string %s bool parsed as %i\n", str.c_str(), b); \
|
||||
} \
|
||||
testAlpha (icp, "False", "False");
|
||||
testAlpha (icp, "fe fi fo fum", "fe");
|
||||
testAlpha (icp, " bla", "");
|
||||
|
||||
BOOL_TEST ("true", true);
|
||||
BOOL_TEST ("True", true);
|
||||
BOOL_TEST ("tRue", true);
|
||||
BOOL_TEST ("TRUE", true);
|
||||
BOOL_TEST ("True", true);
|
||||
BOOL_TEST ("false", false);
|
||||
BOOL_TEST ("False", false);
|
||||
BOOL_TEST ("fAlSe", false);
|
||||
BOOL_TEST ("FALSE", false);
|
||||
BOOL_TEST ("False", false);
|
||||
testBool (icp, "true", true);
|
||||
testBool (icp, "True", true);
|
||||
testBool (icp, "tRue", true);
|
||||
testBool (icp, "TRUE", true);
|
||||
testBool (icp, "True", true);
|
||||
testBool (icp, "false", false);
|
||||
testBool (icp, "False", false);
|
||||
testBool (icp, "fAlSe", false);
|
||||
testBool (icp, "FALSE", false);
|
||||
testBool (icp, "False", false);
|
||||
|
||||
testDouble (icp, "123", 123);
|
||||
testDouble (icp, "12.3", 12.3);
|
||||
testDouble (icp, "-123", -123);
|
||||
testDouble (icp, "-12.3", -12.3);
|
||||
|
||||
testString (icp, "\"fe fi fo fum\"", "fe fi fo fum");
|
||||
testString (icp, "'the tab is ->\\t<- here'", "the tab is ->\t<- here");
|
||||
testString (icp, "'the newline is ->\\n<- here'", "the newline is ->\n<- here");
|
||||
testString (icp, "'the cr is ->\\r<- here'", "the cr is ->\r<- here");
|
||||
testString (icp, "\"an \\\"escaped\\\" string\"", "an \"escaped\" string");
|
||||
|
||||
testUInt32 (icp, "123", 123);
|
||||
testUInt32 (icp, "12.3", 12);
|
||||
testUInt32 (icp, "-123", 0);
|
||||
testUInt32 (icp, "-12.3", 0);
|
||||
/* XXX what to do with the overflow? */
|
||||
//testUInt32 (icp, "12123687213612873621873438754387934657834", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,8 @@
|
||||
|
||||
namespace JavaScript {
|
||||
namespace ICodeASM {
|
||||
|
||||
static char *keyword_offset = "offset";
|
||||
|
||||
int cmp_nocase (const string& s1, string::const_iterator s2_begin,
|
||||
string::const_iterator s2_end)
|
||||
{
|
||||
@ -102,11 +103,21 @@ namespace ICodeASM {
|
||||
tl.begin = curpos;
|
||||
return tl;
|
||||
|
||||
case '-':
|
||||
tl.estimate = teMinus;
|
||||
tl.begin = curpos;
|
||||
return tl;
|
||||
|
||||
case '+':
|
||||
tl.estimate = tePlus;
|
||||
tl.begin = curpos;
|
||||
return tl;
|
||||
|
||||
case ',':
|
||||
tl.estimate = teComma;
|
||||
tl.begin = curpos;
|
||||
return tl;
|
||||
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
tl.estimate = teString;
|
||||
@ -131,7 +142,7 @@ namespace ICodeASM {
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseAlpha (iter begin, iter end, string *rval)
|
||||
ICodeParser::ParseAlpha (iter begin, iter end, string **rval)
|
||||
{
|
||||
iter curpos;
|
||||
string *str = new string();
|
||||
@ -152,7 +163,7 @@ namespace ICodeASM {
|
||||
}
|
||||
scan_done:
|
||||
|
||||
rval = str;
|
||||
*rval = str;
|
||||
return curpos;
|
||||
}
|
||||
|
||||
@ -187,16 +198,31 @@ namespace ICodeASM {
|
||||
ICodeParser::ParseDouble (iter begin, iter end, double *rval)
|
||||
{
|
||||
/* XXX add overflow checking */
|
||||
*rval = 0;
|
||||
uint32 integer;
|
||||
int sign = 1;
|
||||
|
||||
/* pay no attention to the assignment of sign in the test condition :O */
|
||||
if (*begin == '+' || (*begin == '-' && (sign = -1)) {
|
||||
TokenLocation tl = SeekTokenStart (++begin, end);
|
||||
if (tl.estimate != teNumeric)
|
||||
throw new ICodeParseException ("Expected double value");
|
||||
begin = tl.begin;
|
||||
}
|
||||
|
||||
|
||||
iter curpos = ParseUInt32 (begin, end, &integer);
|
||||
*rval = static_cast<double>(integer);
|
||||
if (*curpos != '.')
|
||||
{
|
||||
*rval *= sign;
|
||||
return curpos;
|
||||
}
|
||||
|
||||
++curpos;
|
||||
uint32 position = 0;
|
||||
int32 position = 0;
|
||||
|
||||
for (curpos = begin; curpos < end; ++curpos) {
|
||||
for (; curpos < end; ++curpos) {
|
||||
switch (*curpos)
|
||||
{
|
||||
case '0'...'9':
|
||||
@ -209,19 +235,44 @@ namespace ICodeASM {
|
||||
}
|
||||
scan_done:
|
||||
|
||||
*rval *= sign;
|
||||
|
||||
return curpos;
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseString (iter begin, iter end, string *rval)
|
||||
ICodeParser::ParseInt32 (iter begin, iter end, int32 *rval)
|
||||
{
|
||||
*rval = 0;
|
||||
int sign = 1;
|
||||
|
||||
/* pay no attention to the assignment of sign in the test condition :O */
|
||||
if ((*begin == '+') || (*begin == '-' && (sign = -1))) {
|
||||
TokenLocation tl = SeekTokenStart (++begin, end);
|
||||
if (tl.estimate != teNumeric)
|
||||
throw new ICodeParseException ("Expected int32 value");
|
||||
begin = tl.begin;
|
||||
}
|
||||
|
||||
end = ParseUInt32 (begin, end, rval);
|
||||
|
||||
*rval *= sign;
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseString (iter begin, iter end, string **rval)
|
||||
{
|
||||
char delim = *begin;
|
||||
bool isTerminated = false;
|
||||
/* XXX not exactly exception safe, string may never get deleted */
|
||||
string *str = new string();
|
||||
*rval = 0;
|
||||
|
||||
if (delim != '\'' && delim != '"') {
|
||||
ASSERT ("|begin| does not point at a string");
|
||||
delete str;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -303,7 +354,7 @@ namespace ICodeASM {
|
||||
throw new ICodeParseException ("Unterminated string literal.");
|
||||
}
|
||||
|
||||
rval = str;
|
||||
*rval = str;
|
||||
return curpos;
|
||||
}
|
||||
|
||||
@ -311,7 +362,8 @@ namespace ICodeASM {
|
||||
ICodeParser::ParseUInt32 (iter begin, iter end, uint32 *rval)
|
||||
{
|
||||
/* XXX add overflow checking */
|
||||
int32 position = 0;
|
||||
*rval = 0;
|
||||
int32 position = -1;
|
||||
iter curpos;
|
||||
|
||||
for (curpos = begin; curpos < end; ++curpos) {
|
||||
@ -334,11 +386,17 @@ namespace ICodeASM {
|
||||
return curpos;
|
||||
}
|
||||
|
||||
iter ICodeParser::ParseInstruction (uint icodeID, iter start, iter end)
|
||||
iter ICodeParser::ParseInstruction (uint icodeID, iter begin, iter end)
|
||||
{
|
||||
iter curpos = start;
|
||||
iter curpos = begin;
|
||||
StatementNode *node = new StatementNode();
|
||||
node->begin = begin;
|
||||
node->icodeID = icodeID;
|
||||
|
||||
/* add the node now, so the parse*operand functions can see it (to add
|
||||
* it to the fixup vector, for example.)
|
||||
*/
|
||||
mStatementNodes.push_back (node);
|
||||
|
||||
# define CASE_TYPE(T) \
|
||||
case ot##T: \
|
||||
@ -370,7 +428,7 @@ namespace ICodeASM {
|
||||
}
|
||||
|
||||
# undef CASE_TYPE
|
||||
|
||||
|
||||
return curpos;
|
||||
}
|
||||
|
||||
@ -444,7 +502,7 @@ namespace ICodeASM {
|
||||
if (tl.estimate != teString)
|
||||
throw new ICodeParseException ("Expected BinaryOp as a quoted string.");
|
||||
string *str;
|
||||
end = ParseString (tl.begin, end, str);
|
||||
end = ParseString (tl.begin, end, &str);
|
||||
o->asString = str;
|
||||
return end;
|
||||
}
|
||||
@ -461,11 +519,15 @@ namespace ICodeASM {
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseDoubleOperand (iter begin, iter /*end*/,
|
||||
AnyOperand */*o*/)
|
||||
ICodeParser::ParseDoubleOperand (iter begin, iter end, AnyOperand *o)
|
||||
{
|
||||
ASSERT ("Not Implemented.");
|
||||
return begin;
|
||||
TokenLocation tl = SeekTokenStart (begin, end);
|
||||
|
||||
if ((tl.estimate != teNumeric) && (tl.estimate != teMinus) &&
|
||||
(tl.estimate != tePlus))
|
||||
throw new ICodeParseException ("Expected double value.");
|
||||
|
||||
return ParseDouble (tl.begin, end, &o->asDouble);
|
||||
}
|
||||
|
||||
iter
|
||||
@ -477,49 +539,101 @@ namespace ICodeASM {
|
||||
throw new ICodeParseException ("Expected ICode Module as a quoted string.");
|
||||
|
||||
string *str;
|
||||
end = ParseString (tl.begin, end, str);
|
||||
end = ParseString (tl.begin, end, &str);
|
||||
o->asString = str;
|
||||
return end;
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseJSClassOperand (iter begin, iter /*end*/,
|
||||
AnyOperand */*o*/)
|
||||
ICodeParser::ParseJSClassOperand (iter begin, iter end, AnyOperand *o)
|
||||
{
|
||||
ASSERT ("Not Implemented.");
|
||||
return begin;
|
||||
TokenLocation tl = SeekTokenStart (begin, end);
|
||||
|
||||
if (tl.estimate != teString)
|
||||
throw new ICodeParseException ("Expected JSClass as a quoted string.");
|
||||
|
||||
string *str;
|
||||
end = ParseString (tl.begin, end, &str);
|
||||
o->asString = str;
|
||||
return end;
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseJSStringOperand (iter begin, iter /*end*/,
|
||||
AnyOperand */*o*/)
|
||||
ICodeParser::ParseJSStringOperand (iter begin, iter end, AnyOperand *o)
|
||||
{
|
||||
ASSERT ("Not Implemented.");
|
||||
return begin;
|
||||
TokenLocation tl = SeekTokenStart (begin, end);
|
||||
|
||||
if (tl.estimate != teString)
|
||||
throw new ICodeParseException ("Expected JSString as a quoted string.");
|
||||
|
||||
string *str;
|
||||
end = ParseString (tl.begin, end, &str);
|
||||
o->asString = str;
|
||||
return end;
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseJSFunctionOperand (iter begin, iter /*end*/,
|
||||
AnyOperand */*o*/)
|
||||
ICodeParser::ParseJSFunctionOperand (iter begin, iter end, AnyOperand *o)
|
||||
{
|
||||
ASSERT ("Not Implemented.");
|
||||
return begin;
|
||||
TokenLocation tl = SeekTokenStart (begin, end);
|
||||
|
||||
if (tl.estimate != teString)
|
||||
throw new ICodeParseException ("Expected JSFunction as a quoted string.");
|
||||
|
||||
string *str;
|
||||
end = ParseString (tl.begin, end, &str);
|
||||
o->asString = str;
|
||||
return end;
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseJSTypeOperand (iter begin, iter /*end*/,
|
||||
AnyOperand */*o*/)
|
||||
ICodeParser::ParseJSTypeOperand (iter begin, iter end, AnyOperand *o)
|
||||
{
|
||||
ASSERT ("Not Implemented.");
|
||||
return begin;
|
||||
TokenLocation tl = SeekTokenStart (begin, end);
|
||||
|
||||
if (tl.estimate != teString)
|
||||
throw new ICodeParseException ("Expected JSType as a quoted string.");
|
||||
string *str;
|
||||
end = ParseString (tl.begin, end, &str);
|
||||
o->asString = str;
|
||||
return end;
|
||||
}
|
||||
|
||||
iter
|
||||
ICodeParser::ParseLabelOperand (iter begin, iter /*end*/,
|
||||
AnyOperand */*o*/)
|
||||
ICodeParser::ParseLabelOperand (iter begin, iter end, AnyOperand *o)
|
||||
{
|
||||
ASSERT ("Not Implemented.");
|
||||
return begin;
|
||||
TokenLocation tl = SeekTokenStart (begin, end);
|
||||
|
||||
if (tl.estimate != teAlpha)
|
||||
throw new ICodeParseException ("Expected Label Identifier or Offset keyword.");
|
||||
|
||||
string *str;
|
||||
begin = ParseAlpha (tl.begin, end, &str);
|
||||
|
||||
if (cmp_nocase(*string, keyword_offset, keyword_offset +
|
||||
strlen(keyword_offset) + 1) == 0) {
|
||||
/* label expressed as "Offset +/-N" */
|
||||
tl = SeekTokenStart (begin, end);
|
||||
|
||||
if ((tl.estimate != teNumeric) && (tl.estimate != teMinus) &&
|
||||
(tl.estimate != tePlus))
|
||||
throw new ICodeParseException ("Expected numeric value after Offset keyword.");
|
||||
|
||||
begin = ParseInt32 (tl.begin, end, &(o->asInt32));
|
||||
return begin;
|
||||
} else {
|
||||
/* label expressed as "label_name" */
|
||||
LabelMap::const_iterator l = mLabels.find(str->c_string());
|
||||
if (l == mLabels.end())
|
||||
{
|
||||
/* if we can't find the label, mark it as a fixup for later */
|
||||
o->asString = str;
|
||||
mFixupNodes.push_back (mStatementNodes.back());
|
||||
return begin;
|
||||
}
|
||||
/* XXX continue here... */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
iter
|
||||
|
@ -46,7 +46,9 @@ namespace ICodeASM {
|
||||
teUnknown,
|
||||
teIllegal,
|
||||
teComma,
|
||||
teMinus,
|
||||
teNumeric,
|
||||
tePlus,
|
||||
teAlpha,
|
||||
teString,
|
||||
teNotARegister
|
||||
@ -84,6 +86,7 @@ namespace ICodeASM {
|
||||
/* eww */
|
||||
double asDouble;
|
||||
uint32 asUInt32;
|
||||
int32 asInt32;
|
||||
VM::Register asRegister;
|
||||
bool asBoolean;
|
||||
VM::ArgumentList *asArgumentList;
|
||||
@ -91,6 +94,7 @@ namespace ICodeASM {
|
||||
};
|
||||
|
||||
struct StatementNode {
|
||||
iter pos;
|
||||
uint icodeID;
|
||||
AnyOperand operand[3];
|
||||
};
|
||||
@ -100,7 +104,9 @@ namespace ICodeASM {
|
||||
private:
|
||||
uint mMaxRegister;
|
||||
std::vector<StatementNode *> mStatementNodes;
|
||||
std::map<string, StatementNode **> mLabels;
|
||||
std::vector<StatementNode *> mFixupNodes;
|
||||
typedef std::map<const char *, StatementNode **> LabelMap;
|
||||
LabelMap mLabels;
|
||||
|
||||
public:
|
||||
void ParseSourceFromString (const string source);
|
||||
@ -108,12 +114,17 @@ namespace ICodeASM {
|
||||
/* locate the beginning of the next token, and guess what it might be */
|
||||
TokenLocation SeekTokenStart (iter begin, iter end);
|
||||
|
||||
/* general purpose parse functions */
|
||||
iter ParseAlpha (iter begin, iter end, string *rval);
|
||||
/* general purpose parse functions; |begin| is expected to point
|
||||
* at the start of the token to be processed (eg, these routines
|
||||
* don't call |SeekTokenStart|, and (currently, this might change) no
|
||||
* initial check is done to ensure that |begin| != |end|.
|
||||
*/
|
||||
iter ParseAlpha (iter begin, iter end, string **rval);
|
||||
iter ParseBool (iter begin, iter end, bool *rval);
|
||||
iter ParseDouble (iter begin, iter end, double *rval);
|
||||
iter ParseString (iter begin, iter end, string *rval);
|
||||
iter ParseUInt32 (iter begin, iter end, uint32 *rval);
|
||||
iter ParseDouble (iter begin, iter end, double *rval);
|
||||
iter ParseInt32 (iter begin, iter end, uint32 *rval);
|
||||
iter ParseString (iter begin, iter end, string **rval);
|
||||
iter ParseUInt32 (iter begin, iter end, uint32 *rval);
|
||||
|
||||
/* "high level" parse functions */
|
||||
iter ParseInstruction (uint icodeID, iter start, iter end);
|
||||
|
Loading…
Reference in New Issue
Block a user