more icodeasm work... parse "tree" is finally testable... it might even work.

This commit is contained in:
rginda%netscape.com 2000-10-18 01:02:13 +00:00
parent a428010d2b
commit 9a4a9a865d
6 changed files with 716 additions and 518 deletions

View File

@ -100,6 +100,11 @@ void testUInt32 (JavaScript::ICodeASM::ICodeParser icp, const string &str,
result);
}
void testParse (JavaScript::ICodeASM::ICodeParser icp, const string &str)
{
icp.ParseSourceFromString (str);
}
int
main (int , char **)
{
@ -137,7 +142,19 @@ main (int , char **)
testUInt32 (icp, "-12.3", 0);
/* XXX what to do with the overflow? */
//testUInt32 (icp, "12123687213612873621873438754387934657834", 0);
string src =
"some_label: \
LOAD_STRING R1, 'hello' \
CAST R2, R1, 'any' \
SAVE_NAME 'x', R2 \
LOAD_NAME R1, 'x' \
LOAD_NAME R2, 'print' \
CALL R3, R2, <NaR>, (R1) \
RETURN R3";
testParse (icp, src);
return 0;
}

View File

@ -39,6 +39,9 @@
namespace JavaScript {
namespace ICodeASM {
static char *keyword_offset = "offset";
static char *keyword_binaryops[] = {"add", "subtract", "multiply", "divide",
"remainder", "leftshift", "rightshift",
"lessorequal", "equal", "identical", 0};
int cmp_nocase (const string& s1, string::const_iterator s2_begin,
string::const_iterator s2_end)
@ -57,7 +60,7 @@ namespace ICodeASM {
}
void
ICodeParser::ParseSourceFromString (string source)
ICodeParser::ParseSourceFromString (const string &source)
{
uint statementNo = 0;
@ -80,7 +83,7 @@ namespace ICodeASM {
TokenLocation tl;
iter curpos;
tl.type = ttUndetermined;
// tl.type = ttUndetermined;
for (curpos = begin; curpos < end; ++curpos) {
switch (*curpos)
@ -141,6 +144,10 @@ namespace ICodeASM {
return tl;
}
/**********************************************************************
* general purpose parse functions (see comment in the .h file) ...
*/
iter
ICodeParser::ParseAlpha (iter begin, iter end, string **rval)
{
@ -203,7 +210,7 @@ namespace ICodeASM {
int sign = 1;
/* pay no attention to the assignment of sign in the test condition :O */
if (*begin == '+' || (*begin == '-' && (sign = -1)) {
if (*begin == '+' || (*begin == '-' && (sign = -1))) {
TokenLocation tl = SeekTokenStart (++begin, end);
if (tl.estimate != teNumeric)
throw new ICodeParseException ("Expected double value");
@ -213,8 +220,7 @@ namespace ICodeASM {
iter curpos = ParseUInt32 (begin, end, &integer);
*rval = static_cast<double>(integer);
if (*curpos != '.')
{
if (*curpos != '.') {
*rval *= sign;
return curpos;
}
@ -254,13 +260,43 @@ namespace ICodeASM {
begin = tl.begin;
}
end = ParseUInt32 (begin, end, rval);
uint32 i;
end = ParseUInt32 (begin, end, &i);
*rval *= sign;
*rval = i * sign;
return end;
}
iter
ICodeParser::ParseRegister (iter begin, iter end, JSTypes::Register *rval)
{
if (*begin == 'R' || *begin == 'r') {
if (++begin != end) {
try
{
return ParseUInt32 (++begin, end,
static_cast<uint32 *>(rval));
}
catch (ICodeParseException ex)
{
/* rethrow as an "expected register" in fall through case */
}
}
} else if (*begin != '<') {
if ((++begin != end) && (*begin == 'N' || *begin == 'n'))
if ((++begin != end) && (*begin == 'A' || *begin == 'a'))
if ((++begin != end) && (*begin == 'R' || *begin == 'r'))
if ((++begin != end) &&
(*begin == '>' || *begin == '>')) {
*rval = VM::NotARegister;
return ++begin;
}
}
throw new ICodeParseException ("Expected int32 value");
}
iter
ICodeParser::ParseString (iter begin, iter end, string **rval)
{
@ -386,6 +422,191 @@ namespace ICodeASM {
return curpos;
}
/**********************************************************************
* operand parse functions (see comment in the .h file) ...
*/
iter
ICodeParser::ParseArgumentListOperand (iter begin, iter /*end*/,
VM::ArgumentList **/*o*/)
{
/* XXX this is hard, lets go shopping */
ASSERT ("Not Implemented.");
return begin;
}
iter
ICodeParser::ParseBinaryOpOperand (iter begin, iter end,
VM::BinaryOperator::BinaryOp *rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teAlpha)
throw new ICodeParseException ("Expected BinaryOp.");
string *str;
end = ParseAlpha (tl.begin, end, &str);
for (int i = 0; keyword_binaryops[i] != 0; ++i)
if (cmp_nocase (*str, keyword_binaryops[i], keyword_binaryops[i] +
strlen (keyword_binaryops[i]) + 1) == 0) {
*rval = static_cast<VM::BinaryOperator::BinaryOp>(i);
delete str;
return end;
}
delete str;
throw new ICodeParseException ("Unknown BinaryOp.");
}
iter
ICodeParser::ParseBoolOperand (iter begin, iter end, bool *rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teAlpha)
throw new ICodeParseException ("Expected boolean value.");
return ParseBool (tl.begin, end, rval);
}
iter
ICodeParser::ParseDoubleOperand (iter begin, iter end, double *rval)
{
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, rval);
}
iter
ICodeParser::ParseICodeModuleOperand (iter begin, iter end, string **rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected ICode Module as a quoted string.");
return ParseString (tl.begin, end, rval);
}
iter
ICodeParser::ParseJSClassOperand (iter begin, iter end, string **rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected JSClass as a quoted string.");
return ParseString (tl.begin, end, rval);
}
iter
ICodeParser::ParseJSStringOperand (iter begin, iter end, string **rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected JSString as a quoted string.");
return ParseString (tl.begin, end, rval);
}
iter
ICodeParser::ParseJSFunctionOperand (iter begin, iter end, string **rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected JSFunction as a quoted string.");
return ParseString (tl.begin, end, rval);
}
iter
ICodeParser::ParseJSTypeOperand (iter begin, iter end, string **rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected JSType as a quoted string.");
return ParseString (tl.begin, end, rval);
}
iter
ICodeParser::ParseLabelOperand (iter begin, iter end, VM::Label **rval)
{
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(*str, keyword_offset, keyword_offset +
strlen(keyword_offset) + 1) == 0) {
/* got the "Offset" keyword, treat next thing as a jump offset
* 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.");
int32 ofs;
begin = ParseInt32 (tl.begin, end, &ofs);
VM::Label *new_label = new VM::Label(0);
new_label->mOffset = mStatementNodes.size() + ofs;
mUnnamedLabels.push_back (new_label);
*rval = new_label;
} else {
/* label expressed as "label_name", look for it in the
* namedlabels map */
LabelMap::const_iterator l = mNamedLabels.find(str->c_str());
if (l != mNamedLabels.end()) {
/* found the label, use it */
*rval = (*l).second;
} else {
/* havn't seen the label definition yet, put a placeholder
* in the namedlabels map */
VM::Label *new_label = new VM::Label(0);
new_label->mOffset = VM::NotALabel;
*rval = new_label;
mNamedLabels[str->c_str()] = new_label;
}
}
return begin;
}
iter
ICodeParser::ParseUInt32Operand (iter begin, iter end, uint32 *rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teNumeric)
throw new ICodeParseException ("Expected UInt32 value.");
return ParseUInt32 (tl.begin, end, rval);
}
iter
ICodeParser::ParseRegisterOperand (iter begin, iter end,
JSTypes::Register *rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
return ParseRegister (tl.begin, end, rval);
}
iter
ICodeParser::ParseStringAtomOperand (iter begin, iter end, string **rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected StringAtom as a quoted string.");
return ParseString (tl.begin, end, rval);
}
/* "High Level" parse functions ... */
iter ICodeParser::ParseInstruction (uint icodeID, iter begin, iter end)
{
iter curpos = begin;
@ -393,15 +614,16 @@ namespace ICodeASM {
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.)
*/
/* add the node now, so the parse*operand functions can see it */
mStatementNodes.push_back (node);
# define CASE_TYPE(T) \
# define CASE_TYPE(T, C, CTYPE) \
case ot##T: \
{ \
curpos = Parse##T##Operand (curpos, end, &node->operand[i]); \
C rval; \
node->operand[i].type = ot##T; \
curpos = Parse##T##Operand (curpos, end, &rval); \
node->operand[i].data = CTYPE<int64>(rval); \
break; \
}
@ -409,19 +631,20 @@ namespace ICodeASM {
{
switch (icodemap[icodeID].otype[i])
{
CASE_TYPE(ArgumentList);
CASE_TYPE(BinaryOp);
CASE_TYPE(Bool);
CASE_TYPE(Double);
CASE_TYPE(ICodeModule);
CASE_TYPE(JSClass);
CASE_TYPE(JSString);
CASE_TYPE(JSFunction);
CASE_TYPE(JSType);
CASE_TYPE(Label);
CASE_TYPE(UInt32);
CASE_TYPE(Register);
CASE_TYPE(StringAtom);
CASE_TYPE(ArgumentList, VM::ArgumentList *, reinterpret_cast);
CASE_TYPE(BinaryOp, VM::BinaryOperator::BinaryOp,
static_cast);
CASE_TYPE(Bool, bool, static_cast);
CASE_TYPE(Double, double, static_cast);
CASE_TYPE(ICodeModule, string *, reinterpret_cast);
CASE_TYPE(JSClass, string *, reinterpret_cast);
CASE_TYPE(JSString, string *, reinterpret_cast);
CASE_TYPE(JSFunction, string *, reinterpret_cast);
CASE_TYPE(JSType, string *, reinterpret_cast);
CASE_TYPE(Label, VM::Label *, reinterpret_cast);
CASE_TYPE(UInt32, uint32, static_cast);
CASE_TYPE(Register, JSTypes::Register, static_cast);
CASE_TYPE(StringAtom, string *, reinterpret_cast);
default:
break;
}
@ -435,6 +658,8 @@ namespace ICodeASM {
iter
ICodeParser::ParseStatement (iter begin, iter end)
{
bool isLabel = false;
iter firstTokenEnd = end;
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teAlpha)
@ -444,8 +669,8 @@ namespace ICodeASM {
switch (*curpos)
{
case ':':
tl.type = ttLabel;
tl.end = ++curpos;
isLabel = true;
firstTokenEnd = ++curpos;
goto scan_done;
case 'a'...'z':
@ -455,218 +680,50 @@ namespace ICodeASM {
break;
default:
tl.type = ttInstruction;
tl.end = curpos;
firstTokenEnd = curpos;
goto scan_done;
}
}
scan_done:
if (tl.type == ttUndetermined) {
tl.type = ttInstruction;
tl.end = end;
}
if (tl.type == ttLabel) {
string label_str(tl.begin, tl.end - 1); /* ignore the trailing : */
mLabels[label_str] = mStatementNodes.end();
return tl.end;
} else if (tl.type == ttInstruction) {
string icode_str(tl.begin, tl.end);
if (isLabel) {
/* the thing we scanned was a label...
* ignore the trailing : */
string label_str(tl.begin, firstTokenEnd - 1);
/* check to see if it was already referenced... */
LabelMap::const_iterator l = mNamedLabels.find(label_str.c_str());
if (l == mNamedLabels.end()) {
/* if it wasn't already referenced, add it */
VM::Label *new_label = new VM::Label (0);
new_label->mOffset = mStatementNodes.size();
mNamedLabels[label_str.c_str()] = new_label;
} else {
/* if it was already referenced, check to see if the offset
* was already set */
if ((*l).second->mOffset == VM::NotALabel) {
/* offset not set yet, set it and move along */
(*l).second->mOffset = mStatementNodes.size();
} else {
/* offset was already set, this must be a dupe! */
throw new ICodeParseException ("Duplicate label");
}
}
return firstTokenEnd;
} else {
/* the thing we scanned was an instruction, search the icode map
* for a matching instruction */
string icode_str(tl.begin, firstTokenEnd);
for (uint i = 0; i < icodemap_size; ++i)
if (cmp_nocase(icode_str, &icodemap[i].name[0],
&icodemap[i].name[0] +
strlen(icodemap[i].name) + 1))
return ParseInstruction (i, tl.end, end);
/* if match found, parse it's operands */
return ParseInstruction (i, firstTokenEnd, end);
/* otherwise, choke on it */
throw new ICodeParseException ("Unknown ICode " + icode_str);
} else {
throw new ICodeParseException ("Internal error in ParseStatement.");
}
}
iter
ICodeParser::ParseArgumentListOperand (iter begin, iter /*end*/,
AnyOperand */*o*/)
{
/* XXX this is hard, lets go shopping */
ASSERT ("Not Implemented.");
return begin;
}
iter
ICodeParser::ParseBinaryOpOperand (iter begin, iter end, AnyOperand *o)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected BinaryOp as a quoted string.");
string *str;
end = ParseString (tl.begin, end, &str);
o->asString = str;
return end;
}
iter
ICodeParser::ParseBoolOperand (iter begin, iter end, AnyOperand *o)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teAlpha)
throw new ICodeParseException ("Expected boolean value.");
return ParseBool (tl.begin, end, &o->asBoolean);
}
iter
ICodeParser::ParseDoubleOperand (iter begin, iter end, AnyOperand *o)
{
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
ICodeParser::ParseICodeModuleOperand (iter begin, iter end, AnyOperand *o)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected ICode Module as a quoted string.");
string *str;
end = ParseString (tl.begin, end, &str);
o->asString = str;
return end;
}
iter
ICodeParser::ParseJSClassOperand (iter begin, iter end, AnyOperand *o)
{
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)
{
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)
{
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)
{
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)
{
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) {
/* got the "Offset" keyword, treat next thing as a jump offset
* 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.");
int32 ofs;
begin = ParseInt32 (tl.begin, end, &ofs);
Label *l = new VM::Label(0);
l->mOffset = mStatementNodes.size() + ofs - 1;
mUnnamedLabels.push_back (l);
o->asLabel = l;
} else {
/* label expressed as "label_name", look for it in the
* namedlabels map */
LabelMap::const_iterator l = mLabels.find(str->c_str());
if (l != mLabels.end()) {
/* found the label, use it */
o->asLabel = *l;
} else {
/* havn't seen the label definition yet, put a placeholder
* in the namedlabels map */
VM::Label *new_label = new VM::Label(0);
new_label->mOffset = VM::NotALabel;
o->asLabel = new_label;
mNamedLabels[str] = new_label;
}
}
return begin;
}
iter
ICodeParser::ParseUInt32Operand (iter begin, iter /*end*/,
AnyOperand */*o*/)
{
ASSERT ("Not Implemented.");
return begin;
}
iter
ICodeParser::ParseRegisterOperand (iter begin, iter /*end*/,
AnyOperand */*o*/)
{
ASSERT ("Not Implemented.");
return begin;
}
iter
ICodeParser::ParseStringAtomOperand (iter begin, iter /*end*/,
AnyOperand */*o*/)
{
ASSERT ("Not Implemented.");
return begin;
}
}
}

View File

@ -35,6 +35,7 @@
#include <iterator>
#include "vmtypes.h"
#include "jstypes.h"
#define iter string::const_iterator
@ -54,8 +55,9 @@ namespace ICodeASM {
teNotARegister
};
/*
enum TokenType {
/* verified token type */
// verified token type
ttUndetermined,
ttLabel,
ttInstruction,
@ -66,6 +68,24 @@ namespace ICodeASM {
ttNumber,
ttOffsetKeyword
};
*/
enum OperandType {
otNone = 0,
otArgumentList,
otBinaryOp,
otBool,
otDouble,
otICodeModule,
otJSClass,
otJSString,
otJSFunction,
otJSType,
otLabel,
otUInt32,
otRegister,
otStringAtom
};
struct ICodeParseException {
ICodeParseException (string aMsg, iter aPos = 0)
@ -75,27 +95,21 @@ namespace ICodeASM {
};
struct TokenLocation {
TokenLocation () : begin(0), end(0), estimate(teIllegal),
type(ttUndetermined) {}
iter begin, end;
TokenLocation () : begin(0), estimate(teIllegal) /*,
type(ttUndetermined) */ {}
iter begin;
TokenEstimation estimate;
TokenType type;
// TokenType type;
};
union AnyOperand {
/* eww */
double asDouble;
uint32 asUInt32;
int32 asInt32;
bool asBoolean;
string *asString;
VM::Register asRegister;
VM::Label *asLabel;
VM::ArgumentList *asArgumentList;
struct AnyOperand {
OperandType type;
int64 data;
/*void *data;*/
};
struct StatementNode {
iter pos;
iter begin;
uint icodeID;
AnyOperand operand[3];
};
@ -110,7 +124,7 @@ namespace ICodeASM {
LabelMap mNamedLabels;
public:
void ParseSourceFromString (const string source);
void ParseSourceFromString (const string &source);
/* locate the beginning of the next token and take a guess at what it
* might be */
@ -124,28 +138,39 @@ namespace ICodeASM {
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 ParseInt32 (iter begin, iter end, uint32 *rval);
iter ParseInt32 (iter begin, iter end, int32 *rval);
iter ParseRegister (iter begin, iter end, JSTypes::Register *rval);
iter ParseString (iter begin, iter end, string **rval);
iter ParseUInt32 (iter begin, iter end, uint32 *rval);
/* operand parse functions; These functions take care of finding
* the start of the token with |SeekTokenStart|, and checking the
* "estimation" (explicit checking takes care of |begin| == |end|,
* aka EOF, because EOF is a token estimate.) Once the start of the
* token is found, and it is the expected type, the actual parsing is
* carried out by one of the general purpose parse functions.
*/
iter ParseArgumentListOperand (iter begin, iter end,
VM::ArgumentList **rval);
iter ParseBinaryOpOperand (iter begin, iter end,
VM::BinaryOperator::BinaryOp *rval);
iter ParseBoolOperand (iter begin, iter end, bool *rval);
iter ParseDoubleOperand (iter begin, iter end, double *rval);
iter ParseICodeModuleOperand (iter begin, iter end, string **rval);
iter ParseJSClassOperand (iter begin, iter end, string **rval);
iter ParseJSStringOperand (iter begin, iter end, string **rval);
iter ParseJSFunctionOperand (iter begin, iter end, string **rval);
iter ParseJSTypeOperand (iter begin, iter end, string **rval);
iter ParseLabelOperand (iter begin, iter end, VM::Label **rval);
iter ParseUInt32Operand (iter begin, iter end, uint32 *rval);
iter ParseRegisterOperand (iter begin, iter end,
JSTypes::Register *rval);
iter ParseStringAtomOperand (iter begin, iter end, string **rval);
/* "high level" parse functions */
iter ParseInstruction (uint icodeID, iter start, iter end);
iter ParseStatement (iter begin, iter end);
/* parse particular operand types */
iter ParseArgumentListOperand (iter begin, iter end, AnyOperand *o);
iter ParseBinaryOpOperand (iter begin, iter end, AnyOperand *o);
iter ParseBoolOperand (iter begin, iter end, AnyOperand *o);
iter ParseDoubleOperand (iter begin, iter end, AnyOperand *o);
iter ParseICodeModuleOperand (iter begin, iter end, AnyOperand *o);
iter ParseJSClassOperand (iter begin, iter end, AnyOperand *o);
iter ParseJSStringOperand (iter begin, iter end, AnyOperand *o);
iter ParseJSFunctionOperand (iter begin, iter end, AnyOperand *o);
iter ParseJSTypeOperand (iter begin, iter end, AnyOperand *o);
iter ParseLabelOperand (iter begin, iter end, AnyOperand *o);
iter ParseUInt32Operand (iter begin, iter end, AnyOperand *o);
iter ParseRegisterOperand (iter begin, iter end, AnyOperand *o);
iter ParseStringAtomOperand (iter begin, iter end, AnyOperand *o);
};
}

View File

@ -100,6 +100,11 @@ void testUInt32 (JavaScript::ICodeASM::ICodeParser icp, const string &str,
result);
}
void testParse (JavaScript::ICodeASM::ICodeParser icp, const string &str)
{
icp.ParseSourceFromString (str);
}
int
main (int , char **)
{
@ -137,7 +142,19 @@ main (int , char **)
testUInt32 (icp, "-12.3", 0);
/* XXX what to do with the overflow? */
//testUInt32 (icp, "12123687213612873621873438754387934657834", 0);
string src =
"some_label: \
LOAD_STRING R1, 'hello' \
CAST R2, R1, 'any' \
SAVE_NAME 'x', R2 \
LOAD_NAME R1, 'x' \
LOAD_NAME R2, 'print' \
CALL R3, R2, <NaR>, (R1) \
RETURN R3";
testParse (icp, src);
return 0;
}

View File

@ -39,6 +39,9 @@
namespace JavaScript {
namespace ICodeASM {
static char *keyword_offset = "offset";
static char *keyword_binaryops[] = {"add", "subtract", "multiply", "divide",
"remainder", "leftshift", "rightshift",
"lessorequal", "equal", "identical", 0};
int cmp_nocase (const string& s1, string::const_iterator s2_begin,
string::const_iterator s2_end)
@ -57,7 +60,7 @@ namespace ICodeASM {
}
void
ICodeParser::ParseSourceFromString (string source)
ICodeParser::ParseSourceFromString (const string &source)
{
uint statementNo = 0;
@ -80,7 +83,7 @@ namespace ICodeASM {
TokenLocation tl;
iter curpos;
tl.type = ttUndetermined;
// tl.type = ttUndetermined;
for (curpos = begin; curpos < end; ++curpos) {
switch (*curpos)
@ -141,6 +144,10 @@ namespace ICodeASM {
return tl;
}
/**********************************************************************
* general purpose parse functions (see comment in the .h file) ...
*/
iter
ICodeParser::ParseAlpha (iter begin, iter end, string **rval)
{
@ -203,7 +210,7 @@ namespace ICodeASM {
int sign = 1;
/* pay no attention to the assignment of sign in the test condition :O */
if (*begin == '+' || (*begin == '-' && (sign = -1)) {
if (*begin == '+' || (*begin == '-' && (sign = -1))) {
TokenLocation tl = SeekTokenStart (++begin, end);
if (tl.estimate != teNumeric)
throw new ICodeParseException ("Expected double value");
@ -213,8 +220,7 @@ namespace ICodeASM {
iter curpos = ParseUInt32 (begin, end, &integer);
*rval = static_cast<double>(integer);
if (*curpos != '.')
{
if (*curpos != '.') {
*rval *= sign;
return curpos;
}
@ -254,13 +260,43 @@ namespace ICodeASM {
begin = tl.begin;
}
end = ParseUInt32 (begin, end, rval);
uint32 i;
end = ParseUInt32 (begin, end, &i);
*rval *= sign;
*rval = i * sign;
return end;
}
iter
ICodeParser::ParseRegister (iter begin, iter end, JSTypes::Register *rval)
{
if (*begin == 'R' || *begin == 'r') {
if (++begin != end) {
try
{
return ParseUInt32 (++begin, end,
static_cast<uint32 *>(rval));
}
catch (ICodeParseException ex)
{
/* rethrow as an "expected register" in fall through case */
}
}
} else if (*begin != '<') {
if ((++begin != end) && (*begin == 'N' || *begin == 'n'))
if ((++begin != end) && (*begin == 'A' || *begin == 'a'))
if ((++begin != end) && (*begin == 'R' || *begin == 'r'))
if ((++begin != end) &&
(*begin == '>' || *begin == '>')) {
*rval = VM::NotARegister;
return ++begin;
}
}
throw new ICodeParseException ("Expected int32 value");
}
iter
ICodeParser::ParseString (iter begin, iter end, string **rval)
{
@ -386,6 +422,191 @@ namespace ICodeASM {
return curpos;
}
/**********************************************************************
* operand parse functions (see comment in the .h file) ...
*/
iter
ICodeParser::ParseArgumentListOperand (iter begin, iter /*end*/,
VM::ArgumentList **/*o*/)
{
/* XXX this is hard, lets go shopping */
ASSERT ("Not Implemented.");
return begin;
}
iter
ICodeParser::ParseBinaryOpOperand (iter begin, iter end,
VM::BinaryOperator::BinaryOp *rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teAlpha)
throw new ICodeParseException ("Expected BinaryOp.");
string *str;
end = ParseAlpha (tl.begin, end, &str);
for (int i = 0; keyword_binaryops[i] != 0; ++i)
if (cmp_nocase (*str, keyword_binaryops[i], keyword_binaryops[i] +
strlen (keyword_binaryops[i]) + 1) == 0) {
*rval = static_cast<VM::BinaryOperator::BinaryOp>(i);
delete str;
return end;
}
delete str;
throw new ICodeParseException ("Unknown BinaryOp.");
}
iter
ICodeParser::ParseBoolOperand (iter begin, iter end, bool *rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teAlpha)
throw new ICodeParseException ("Expected boolean value.");
return ParseBool (tl.begin, end, rval);
}
iter
ICodeParser::ParseDoubleOperand (iter begin, iter end, double *rval)
{
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, rval);
}
iter
ICodeParser::ParseICodeModuleOperand (iter begin, iter end, string **rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected ICode Module as a quoted string.");
return ParseString (tl.begin, end, rval);
}
iter
ICodeParser::ParseJSClassOperand (iter begin, iter end, string **rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected JSClass as a quoted string.");
return ParseString (tl.begin, end, rval);
}
iter
ICodeParser::ParseJSStringOperand (iter begin, iter end, string **rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected JSString as a quoted string.");
return ParseString (tl.begin, end, rval);
}
iter
ICodeParser::ParseJSFunctionOperand (iter begin, iter end, string **rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected JSFunction as a quoted string.");
return ParseString (tl.begin, end, rval);
}
iter
ICodeParser::ParseJSTypeOperand (iter begin, iter end, string **rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected JSType as a quoted string.");
return ParseString (tl.begin, end, rval);
}
iter
ICodeParser::ParseLabelOperand (iter begin, iter end, VM::Label **rval)
{
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(*str, keyword_offset, keyword_offset +
strlen(keyword_offset) + 1) == 0) {
/* got the "Offset" keyword, treat next thing as a jump offset
* 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.");
int32 ofs;
begin = ParseInt32 (tl.begin, end, &ofs);
VM::Label *new_label = new VM::Label(0);
new_label->mOffset = mStatementNodes.size() + ofs;
mUnnamedLabels.push_back (new_label);
*rval = new_label;
} else {
/* label expressed as "label_name", look for it in the
* namedlabels map */
LabelMap::const_iterator l = mNamedLabels.find(str->c_str());
if (l != mNamedLabels.end()) {
/* found the label, use it */
*rval = (*l).second;
} else {
/* havn't seen the label definition yet, put a placeholder
* in the namedlabels map */
VM::Label *new_label = new VM::Label(0);
new_label->mOffset = VM::NotALabel;
*rval = new_label;
mNamedLabels[str->c_str()] = new_label;
}
}
return begin;
}
iter
ICodeParser::ParseUInt32Operand (iter begin, iter end, uint32 *rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teNumeric)
throw new ICodeParseException ("Expected UInt32 value.");
return ParseUInt32 (tl.begin, end, rval);
}
iter
ICodeParser::ParseRegisterOperand (iter begin, iter end,
JSTypes::Register *rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
return ParseRegister (tl.begin, end, rval);
}
iter
ICodeParser::ParseStringAtomOperand (iter begin, iter end, string **rval)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected StringAtom as a quoted string.");
return ParseString (tl.begin, end, rval);
}
/* "High Level" parse functions ... */
iter ICodeParser::ParseInstruction (uint icodeID, iter begin, iter end)
{
iter curpos = begin;
@ -393,15 +614,16 @@ namespace ICodeASM {
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.)
*/
/* add the node now, so the parse*operand functions can see it */
mStatementNodes.push_back (node);
# define CASE_TYPE(T) \
# define CASE_TYPE(T, C, CTYPE) \
case ot##T: \
{ \
curpos = Parse##T##Operand (curpos, end, &node->operand[i]); \
C rval; \
node->operand[i].type = ot##T; \
curpos = Parse##T##Operand (curpos, end, &rval); \
node->operand[i].data = CTYPE<int64>(rval); \
break; \
}
@ -409,19 +631,20 @@ namespace ICodeASM {
{
switch (icodemap[icodeID].otype[i])
{
CASE_TYPE(ArgumentList);
CASE_TYPE(BinaryOp);
CASE_TYPE(Bool);
CASE_TYPE(Double);
CASE_TYPE(ICodeModule);
CASE_TYPE(JSClass);
CASE_TYPE(JSString);
CASE_TYPE(JSFunction);
CASE_TYPE(JSType);
CASE_TYPE(Label);
CASE_TYPE(UInt32);
CASE_TYPE(Register);
CASE_TYPE(StringAtom);
CASE_TYPE(ArgumentList, VM::ArgumentList *, reinterpret_cast);
CASE_TYPE(BinaryOp, VM::BinaryOperator::BinaryOp,
static_cast);
CASE_TYPE(Bool, bool, static_cast);
CASE_TYPE(Double, double, static_cast);
CASE_TYPE(ICodeModule, string *, reinterpret_cast);
CASE_TYPE(JSClass, string *, reinterpret_cast);
CASE_TYPE(JSString, string *, reinterpret_cast);
CASE_TYPE(JSFunction, string *, reinterpret_cast);
CASE_TYPE(JSType, string *, reinterpret_cast);
CASE_TYPE(Label, VM::Label *, reinterpret_cast);
CASE_TYPE(UInt32, uint32, static_cast);
CASE_TYPE(Register, JSTypes::Register, static_cast);
CASE_TYPE(StringAtom, string *, reinterpret_cast);
default:
break;
}
@ -435,6 +658,8 @@ namespace ICodeASM {
iter
ICodeParser::ParseStatement (iter begin, iter end)
{
bool isLabel = false;
iter firstTokenEnd = end;
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teAlpha)
@ -444,8 +669,8 @@ namespace ICodeASM {
switch (*curpos)
{
case ':':
tl.type = ttLabel;
tl.end = ++curpos;
isLabel = true;
firstTokenEnd = ++curpos;
goto scan_done;
case 'a'...'z':
@ -455,218 +680,50 @@ namespace ICodeASM {
break;
default:
tl.type = ttInstruction;
tl.end = curpos;
firstTokenEnd = curpos;
goto scan_done;
}
}
scan_done:
if (tl.type == ttUndetermined) {
tl.type = ttInstruction;
tl.end = end;
}
if (tl.type == ttLabel) {
string label_str(tl.begin, tl.end - 1); /* ignore the trailing : */
mLabels[label_str] = mStatementNodes.end();
return tl.end;
} else if (tl.type == ttInstruction) {
string icode_str(tl.begin, tl.end);
if (isLabel) {
/* the thing we scanned was a label...
* ignore the trailing : */
string label_str(tl.begin, firstTokenEnd - 1);
/* check to see if it was already referenced... */
LabelMap::const_iterator l = mNamedLabels.find(label_str.c_str());
if (l == mNamedLabels.end()) {
/* if it wasn't already referenced, add it */
VM::Label *new_label = new VM::Label (0);
new_label->mOffset = mStatementNodes.size();
mNamedLabels[label_str.c_str()] = new_label;
} else {
/* if it was already referenced, check to see if the offset
* was already set */
if ((*l).second->mOffset == VM::NotALabel) {
/* offset not set yet, set it and move along */
(*l).second->mOffset = mStatementNodes.size();
} else {
/* offset was already set, this must be a dupe! */
throw new ICodeParseException ("Duplicate label");
}
}
return firstTokenEnd;
} else {
/* the thing we scanned was an instruction, search the icode map
* for a matching instruction */
string icode_str(tl.begin, firstTokenEnd);
for (uint i = 0; i < icodemap_size; ++i)
if (cmp_nocase(icode_str, &icodemap[i].name[0],
&icodemap[i].name[0] +
strlen(icodemap[i].name) + 1))
return ParseInstruction (i, tl.end, end);
/* if match found, parse it's operands */
return ParseInstruction (i, firstTokenEnd, end);
/* otherwise, choke on it */
throw new ICodeParseException ("Unknown ICode " + icode_str);
} else {
throw new ICodeParseException ("Internal error in ParseStatement.");
}
}
iter
ICodeParser::ParseArgumentListOperand (iter begin, iter /*end*/,
AnyOperand */*o*/)
{
/* XXX this is hard, lets go shopping */
ASSERT ("Not Implemented.");
return begin;
}
iter
ICodeParser::ParseBinaryOpOperand (iter begin, iter end, AnyOperand *o)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected BinaryOp as a quoted string.");
string *str;
end = ParseString (tl.begin, end, &str);
o->asString = str;
return end;
}
iter
ICodeParser::ParseBoolOperand (iter begin, iter end, AnyOperand *o)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teAlpha)
throw new ICodeParseException ("Expected boolean value.");
return ParseBool (tl.begin, end, &o->asBoolean);
}
iter
ICodeParser::ParseDoubleOperand (iter begin, iter end, AnyOperand *o)
{
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
ICodeParser::ParseICodeModuleOperand (iter begin, iter end, AnyOperand *o)
{
TokenLocation tl = SeekTokenStart (begin, end);
if (tl.estimate != teString)
throw new ICodeParseException ("Expected ICode Module as a quoted string.");
string *str;
end = ParseString (tl.begin, end, &str);
o->asString = str;
return end;
}
iter
ICodeParser::ParseJSClassOperand (iter begin, iter end, AnyOperand *o)
{
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)
{
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)
{
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)
{
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)
{
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) {
/* got the "Offset" keyword, treat next thing as a jump offset
* 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.");
int32 ofs;
begin = ParseInt32 (tl.begin, end, &ofs);
Label *l = new VM::Label(0);
l->mOffset = mStatementNodes.size() + ofs - 1;
mUnnamedLabels.push_back (l);
o->asLabel = l;
} else {
/* label expressed as "label_name", look for it in the
* namedlabels map */
LabelMap::const_iterator l = mLabels.find(str->c_str());
if (l != mLabels.end()) {
/* found the label, use it */
o->asLabel = *l;
} else {
/* havn't seen the label definition yet, put a placeholder
* in the namedlabels map */
VM::Label *new_label = new VM::Label(0);
new_label->mOffset = VM::NotALabel;
o->asLabel = new_label;
mNamedLabels[str] = new_label;
}
}
return begin;
}
iter
ICodeParser::ParseUInt32Operand (iter begin, iter /*end*/,
AnyOperand */*o*/)
{
ASSERT ("Not Implemented.");
return begin;
}
iter
ICodeParser::ParseRegisterOperand (iter begin, iter /*end*/,
AnyOperand */*o*/)
{
ASSERT ("Not Implemented.");
return begin;
}
iter
ICodeParser::ParseStringAtomOperand (iter begin, iter /*end*/,
AnyOperand */*o*/)
{
ASSERT ("Not Implemented.");
return begin;
}
}
}

View File

@ -35,6 +35,7 @@
#include <iterator>
#include "vmtypes.h"
#include "jstypes.h"
#define iter string::const_iterator
@ -54,8 +55,9 @@ namespace ICodeASM {
teNotARegister
};
/*
enum TokenType {
/* verified token type */
// verified token type
ttUndetermined,
ttLabel,
ttInstruction,
@ -66,6 +68,24 @@ namespace ICodeASM {
ttNumber,
ttOffsetKeyword
};
*/
enum OperandType {
otNone = 0,
otArgumentList,
otBinaryOp,
otBool,
otDouble,
otICodeModule,
otJSClass,
otJSString,
otJSFunction,
otJSType,
otLabel,
otUInt32,
otRegister,
otStringAtom
};
struct ICodeParseException {
ICodeParseException (string aMsg, iter aPos = 0)
@ -75,27 +95,21 @@ namespace ICodeASM {
};
struct TokenLocation {
TokenLocation () : begin(0), end(0), estimate(teIllegal),
type(ttUndetermined) {}
iter begin, end;
TokenLocation () : begin(0), estimate(teIllegal) /*,
type(ttUndetermined) */ {}
iter begin;
TokenEstimation estimate;
TokenType type;
// TokenType type;
};
union AnyOperand {
/* eww */
double asDouble;
uint32 asUInt32;
int32 asInt32;
bool asBoolean;
string *asString;
VM::Register asRegister;
VM::Label *asLabel;
VM::ArgumentList *asArgumentList;
struct AnyOperand {
OperandType type;
int64 data;
/*void *data;*/
};
struct StatementNode {
iter pos;
iter begin;
uint icodeID;
AnyOperand operand[3];
};
@ -110,7 +124,7 @@ namespace ICodeASM {
LabelMap mNamedLabels;
public:
void ParseSourceFromString (const string source);
void ParseSourceFromString (const string &source);
/* locate the beginning of the next token and take a guess at what it
* might be */
@ -124,28 +138,39 @@ namespace ICodeASM {
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 ParseInt32 (iter begin, iter end, uint32 *rval);
iter ParseInt32 (iter begin, iter end, int32 *rval);
iter ParseRegister (iter begin, iter end, JSTypes::Register *rval);
iter ParseString (iter begin, iter end, string **rval);
iter ParseUInt32 (iter begin, iter end, uint32 *rval);
/* operand parse functions; These functions take care of finding
* the start of the token with |SeekTokenStart|, and checking the
* "estimation" (explicit checking takes care of |begin| == |end|,
* aka EOF, because EOF is a token estimate.) Once the start of the
* token is found, and it is the expected type, the actual parsing is
* carried out by one of the general purpose parse functions.
*/
iter ParseArgumentListOperand (iter begin, iter end,
VM::ArgumentList **rval);
iter ParseBinaryOpOperand (iter begin, iter end,
VM::BinaryOperator::BinaryOp *rval);
iter ParseBoolOperand (iter begin, iter end, bool *rval);
iter ParseDoubleOperand (iter begin, iter end, double *rval);
iter ParseICodeModuleOperand (iter begin, iter end, string **rval);
iter ParseJSClassOperand (iter begin, iter end, string **rval);
iter ParseJSStringOperand (iter begin, iter end, string **rval);
iter ParseJSFunctionOperand (iter begin, iter end, string **rval);
iter ParseJSTypeOperand (iter begin, iter end, string **rval);
iter ParseLabelOperand (iter begin, iter end, VM::Label **rval);
iter ParseUInt32Operand (iter begin, iter end, uint32 *rval);
iter ParseRegisterOperand (iter begin, iter end,
JSTypes::Register *rval);
iter ParseStringAtomOperand (iter begin, iter end, string **rval);
/* "high level" parse functions */
iter ParseInstruction (uint icodeID, iter start, iter end);
iter ParseStatement (iter begin, iter end);
/* parse particular operand types */
iter ParseArgumentListOperand (iter begin, iter end, AnyOperand *o);
iter ParseBinaryOpOperand (iter begin, iter end, AnyOperand *o);
iter ParseBoolOperand (iter begin, iter end, AnyOperand *o);
iter ParseDoubleOperand (iter begin, iter end, AnyOperand *o);
iter ParseICodeModuleOperand (iter begin, iter end, AnyOperand *o);
iter ParseJSClassOperand (iter begin, iter end, AnyOperand *o);
iter ParseJSStringOperand (iter begin, iter end, AnyOperand *o);
iter ParseJSFunctionOperand (iter begin, iter end, AnyOperand *o);
iter ParseJSTypeOperand (iter begin, iter end, AnyOperand *o);
iter ParseLabelOperand (iter begin, iter end, AnyOperand *o);
iter ParseUInt32Operand (iter begin, iter end, AnyOperand *o);
iter ParseRegisterOperand (iter begin, iter end, AnyOperand *o);
iter ParseStringAtomOperand (iter begin, iter end, AnyOperand *o);
};
}