2000-10-11 06:44:14 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Netscape Public
|
|
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy of
|
|
|
|
* the License at http://www.mozilla.org/NPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS
|
|
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
|
|
|
|
* implied. See the License for the specific language governing
|
|
|
|
* rights and limitations under the License.
|
|
|
|
*
|
|
|
|
* The Original Code is the JavaScript 2 Prototype.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape
|
|
|
|
* Communications Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the
|
|
|
|
* terms of the GNU Public License (the "GPL"), in which case the
|
|
|
|
* provisions of the GPL are applicable instead of those above.
|
|
|
|
* If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of the GPL and not to allow others to use your
|
|
|
|
* version of this file under the NPL, indicate your decision by
|
|
|
|
* deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this
|
|
|
|
* file under either the NPL or the GPL.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2000-10-12 05:32:01 +04:00
|
|
|
#include "icodeasm.h"
|
2000-10-11 06:44:14 +04:00
|
|
|
#include "icodemap.h"
|
|
|
|
|
|
|
|
namespace JavaScript {
|
|
|
|
namespace ICodeASM {
|
2000-10-17 04:41:54 +04:00
|
|
|
static char *keyword_offset = "offset";
|
2000-10-18 05:02:13 +04:00
|
|
|
static char *keyword_binaryops[] = {"add", "subtract", "multiply", "divide",
|
|
|
|
"remainder", "leftshift", "rightshift",
|
|
|
|
"lessorequal", "equal", "identical", 0};
|
2000-10-17 04:41:54 +04:00
|
|
|
|
2000-10-13 03:58:51 +04:00
|
|
|
int cmp_nocase (const string& s1, string::const_iterator s2_begin,
|
|
|
|
string::const_iterator s2_end)
|
|
|
|
{
|
|
|
|
string::const_iterator p1 = s1.begin();
|
|
|
|
string::const_iterator p2 = s2_begin;
|
2000-10-18 07:12:42 +04:00
|
|
|
uint s2_size = s2_end - s2_begin - 1;
|
2000-10-13 03:58:51 +04:00
|
|
|
|
|
|
|
while (p1 != s1.end() && p2 != s2_end) {
|
|
|
|
if (toupper(*p1) != toupper(*p2))
|
|
|
|
return (toupper(*p1) < toupper(*p2)) ? -1 : 1;
|
|
|
|
++p1; ++p2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (s1.size() == s2_size) ? 0 : (s1.size() < s2_size) ? -1 : 1;
|
|
|
|
}
|
|
|
|
|
2000-10-11 06:44:14 +04:00
|
|
|
void
|
2000-10-18 05:02:13 +04:00
|
|
|
ICodeParser::ParseSourceFromString (const string &source)
|
2000-10-11 06:44:14 +04:00
|
|
|
{
|
2000-10-12 05:32:01 +04:00
|
|
|
uint statementNo = 0;
|
2000-10-18 07:12:42 +04:00
|
|
|
iter begin = source.begin();
|
|
|
|
iter end = source.end();
|
|
|
|
|
|
|
|
while (begin != end)
|
2000-10-11 06:44:14 +04:00
|
|
|
{
|
2000-10-18 07:12:42 +04:00
|
|
|
try
|
|
|
|
{
|
|
|
|
++statementNo;
|
|
|
|
begin = ParseStatement (begin, end);
|
|
|
|
}
|
|
|
|
catch (ICodeParseException *e)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "Parse Error: %s at statement %u\n",
|
|
|
|
e->msg.c_str(), statementNo);
|
|
|
|
delete e;
|
|
|
|
return;
|
|
|
|
}
|
2000-10-11 06:44:14 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TokenLocation
|
|
|
|
ICodeParser::SeekTokenStart (iter begin, iter end)
|
|
|
|
{
|
|
|
|
TokenLocation tl;
|
|
|
|
iter curpos;
|
|
|
|
|
2000-10-18 05:02:13 +04:00
|
|
|
// tl.type = ttUndetermined;
|
2000-10-11 06:44:14 +04:00
|
|
|
|
|
|
|
for (curpos = begin; curpos < end; ++curpos) {
|
|
|
|
switch (*curpos)
|
|
|
|
{
|
|
|
|
case ' ':
|
|
|
|
case '\t':
|
|
|
|
case '\n':
|
|
|
|
/* look past the whitespace */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'a'...'z':
|
|
|
|
case 'A'...'Z':
|
2000-10-12 05:32:01 +04:00
|
|
|
case '_':
|
2000-10-11 06:44:14 +04:00
|
|
|
tl.estimate = teAlpha;
|
|
|
|
tl.begin = curpos;
|
|
|
|
return tl;
|
|
|
|
|
2000-10-12 05:32:01 +04:00
|
|
|
case '0'...'9':
|
2000-10-11 06:44:14 +04:00
|
|
|
tl.estimate = teNumeric;
|
|
|
|
tl.begin = curpos;
|
|
|
|
return tl;
|
|
|
|
|
2000-10-17 04:41:54 +04:00
|
|
|
case '-':
|
|
|
|
tl.estimate = teMinus;
|
|
|
|
tl.begin = curpos;
|
|
|
|
return tl;
|
|
|
|
|
|
|
|
case '+':
|
|
|
|
tl.estimate = tePlus;
|
|
|
|
tl.begin = curpos;
|
|
|
|
return tl;
|
|
|
|
|
2000-10-11 06:44:14 +04:00
|
|
|
case ',':
|
|
|
|
tl.estimate = teComma;
|
|
|
|
tl.begin = curpos;
|
|
|
|
return tl;
|
2000-10-17 04:41:54 +04:00
|
|
|
|
2000-10-11 06:44:14 +04:00
|
|
|
case '"':
|
|
|
|
case '\'':
|
|
|
|
tl.estimate = teString;
|
|
|
|
tl.begin = curpos;
|
|
|
|
return tl;
|
|
|
|
|
|
|
|
case '<':
|
|
|
|
tl.estimate = teNotARegister;
|
|
|
|
tl.begin = curpos;
|
|
|
|
return tl;
|
|
|
|
|
2000-10-18 07:12:42 +04:00
|
|
|
case '(':
|
|
|
|
tl.estimate = teOpenParen;
|
|
|
|
tl.begin = curpos;
|
|
|
|
return tl;
|
|
|
|
|
|
|
|
case ')':
|
|
|
|
tl.estimate = teCloseParen;
|
|
|
|
tl.begin = curpos;
|
|
|
|
return tl;
|
|
|
|
|
|
|
|
case ':':
|
|
|
|
tl.estimate = teColon;
|
|
|
|
tl.begin = curpos;
|
|
|
|
return tl;
|
|
|
|
|
2000-10-11 06:44:14 +04:00
|
|
|
default:
|
|
|
|
tl.estimate = teUnknown;
|
|
|
|
tl.begin = curpos;
|
|
|
|
return tl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tl.begin = curpos;
|
|
|
|
tl.estimate = teEOF;
|
|
|
|
return tl;
|
|
|
|
}
|
|
|
|
|
2000-10-18 05:02:13 +04:00
|
|
|
/**********************************************************************
|
|
|
|
* general purpose parse functions (see comment in the .h file) ...
|
|
|
|
*/
|
|
|
|
|
2000-10-12 11:55:13 +04:00
|
|
|
iter
|
2000-10-17 04:41:54 +04:00
|
|
|
ICodeParser::ParseAlpha (iter begin, iter end, string **rval)
|
2000-10-12 11:55:13 +04:00
|
|
|
{
|
|
|
|
iter curpos;
|
2000-10-13 03:58:51 +04:00
|
|
|
string *str = new string();
|
2000-10-12 11:55:13 +04:00
|
|
|
|
|
|
|
for (curpos = begin; curpos < end; ++curpos) {
|
|
|
|
switch (*curpos)
|
|
|
|
{
|
2000-10-13 03:58:51 +04:00
|
|
|
case 'a'...'z':
|
|
|
|
case 'A'...'Z':
|
2000-10-12 11:55:13 +04:00
|
|
|
case '0'...'9':
|
2000-10-13 03:58:51 +04:00
|
|
|
case '_':
|
|
|
|
*str += *curpos;
|
2000-10-12 11:55:13 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2000-10-13 03:58:51 +04:00
|
|
|
goto scan_done;
|
2000-10-12 11:55:13 +04:00
|
|
|
}
|
|
|
|
}
|
2000-10-13 03:58:51 +04:00
|
|
|
scan_done:
|
2000-10-12 11:55:13 +04:00
|
|
|
|
2000-10-17 04:41:54 +04:00
|
|
|
*rval = str;
|
2000-10-12 11:55:13 +04:00
|
|
|
return curpos;
|
|
|
|
}
|
|
|
|
|
2000-10-13 03:58:51 +04:00
|
|
|
iter
|
|
|
|
ICodeParser::ParseBool (iter begin, iter end, bool *rval)
|
|
|
|
{
|
|
|
|
iter curpos = begin;
|
|
|
|
|
2000-10-14 04:06:42 +04:00
|
|
|
if ((curpos != end) && (*curpos == 'T' || *curpos == 't')) {
|
|
|
|
if ((++curpos != end) && (*curpos == 'R' || *curpos == 'r'))
|
|
|
|
if ((++curpos != end) && (*curpos == 'U' || *curpos == 'u'))
|
2000-10-13 03:58:51 +04:00
|
|
|
if ((++curpos != end) &&
|
2000-10-14 04:06:42 +04:00
|
|
|
(*curpos == 'E' || *curpos == 'e')) {
|
2000-10-13 03:58:51 +04:00
|
|
|
*rval = true;
|
|
|
|
return ++curpos;
|
|
|
|
}
|
2000-10-14 04:06:42 +04:00
|
|
|
} else if ((curpos != end) && (*curpos == 'F' || *curpos == 'f')) {
|
|
|
|
if ((++curpos != end) && (*curpos == 'A' || *curpos == 'a'))
|
|
|
|
if ((++curpos != end) && (*curpos == 'L' || *curpos == 'l'))
|
|
|
|
if ((++curpos != end) && (*curpos == 'S' || *curpos == 's'))
|
2000-10-13 03:58:51 +04:00
|
|
|
if ((++curpos != end) &&
|
2000-10-14 04:06:42 +04:00
|
|
|
(*curpos == 'E' || *curpos == 'e')) {
|
2000-10-13 03:58:51 +04:00
|
|
|
*rval = false;
|
|
|
|
return ++curpos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Expected boolean value");
|
2000-10-13 03:58:51 +04:00
|
|
|
}
|
|
|
|
|
2000-10-12 11:55:13 +04:00
|
|
|
iter
|
|
|
|
ICodeParser::ParseDouble (iter begin, iter end, double *rval)
|
|
|
|
{
|
2000-10-13 03:58:51 +04:00
|
|
|
/* XXX add overflow checking */
|
2000-10-17 04:41:54 +04:00
|
|
|
*rval = 0;
|
2000-10-13 03:58:51 +04:00
|
|
|
uint32 integer;
|
2000-10-17 04:41:54 +04:00
|
|
|
int sign = 1;
|
|
|
|
|
|
|
|
/* pay no attention to the assignment of sign in the test condition :O */
|
2000-10-18 05:02:13 +04:00
|
|
|
if (*begin == '+' || (*begin == '-' && (sign = -1))) {
|
2000-10-17 04:41:54 +04:00
|
|
|
TokenLocation tl = SeekTokenStart (++begin, end);
|
|
|
|
if (tl.estimate != teNumeric)
|
|
|
|
throw new ICodeParseException ("Expected double value");
|
|
|
|
begin = tl.begin;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-10-13 03:58:51 +04:00
|
|
|
iter curpos = ParseUInt32 (begin, end, &integer);
|
2000-10-12 11:55:13 +04:00
|
|
|
*rval = static_cast<double>(integer);
|
2000-10-18 05:02:13 +04:00
|
|
|
if (*curpos != '.') {
|
2000-10-17 04:41:54 +04:00
|
|
|
*rval *= sign;
|
2000-10-12 11:55:13 +04:00
|
|
|
return curpos;
|
2000-10-17 04:41:54 +04:00
|
|
|
}
|
2000-10-12 11:55:13 +04:00
|
|
|
|
|
|
|
++curpos;
|
2000-10-17 04:41:54 +04:00
|
|
|
int32 position = 0;
|
2000-10-12 11:55:13 +04:00
|
|
|
|
2000-10-17 04:41:54 +04:00
|
|
|
for (; curpos < end; ++curpos) {
|
2000-10-12 11:55:13 +04:00
|
|
|
switch (*curpos)
|
|
|
|
{
|
|
|
|
case '0'...'9':
|
|
|
|
*rval += (*curpos - '0') * (1 / pow (10, ++position));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2000-10-13 03:58:51 +04:00
|
|
|
goto scan_done;
|
2000-10-12 11:55:13 +04:00
|
|
|
}
|
|
|
|
}
|
2000-10-13 03:58:51 +04:00
|
|
|
scan_done:
|
2000-10-12 11:55:13 +04:00
|
|
|
|
2000-10-17 04:41:54 +04:00
|
|
|
*rval *= sign;
|
|
|
|
|
2000-10-12 11:55:13 +04:00
|
|
|
return curpos;
|
|
|
|
}
|
|
|
|
|
|
|
|
iter
|
2000-10-17 04:41:54 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2000-10-18 05:02:13 +04:00
|
|
|
uint32 i;
|
|
|
|
end = ParseUInt32 (begin, end, &i);
|
2000-10-17 04:41:54 +04:00
|
|
|
|
2000-10-18 05:02:13 +04:00
|
|
|
*rval = i * sign;
|
2000-10-17 04:41:54 +04:00
|
|
|
|
|
|
|
return end;
|
|
|
|
}
|
|
|
|
|
2000-10-18 05:02:13 +04:00
|
|
|
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));
|
|
|
|
}
|
2000-10-18 07:12:42 +04:00
|
|
|
catch (ICodeParseException *e)
|
2000-10-18 05:02:13 +04:00
|
|
|
{
|
|
|
|
/* rethrow as an "expected register" in fall through case */
|
2000-10-18 07:12:42 +04:00
|
|
|
delete e;
|
2000-10-18 05:02:13 +04:00
|
|
|
}
|
|
|
|
}
|
2000-10-18 07:12:42 +04:00
|
|
|
} else if (*begin == '<') {
|
2000-10-18 05:02:13 +04:00
|
|
|
if ((++begin != end) && (*begin == 'N' || *begin == 'n'))
|
|
|
|
if ((++begin != end) && (*begin == 'A' || *begin == 'a'))
|
|
|
|
if ((++begin != end) && (*begin == 'R' || *begin == 'r'))
|
2000-10-18 07:12:42 +04:00
|
|
|
if ((++begin != end) && *begin == '>') {
|
2000-10-18 05:02:13 +04:00
|
|
|
*rval = VM::NotARegister;
|
|
|
|
return ++begin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Expected Register value");
|
2000-10-18 05:02:13 +04:00
|
|
|
}
|
|
|
|
|
2000-10-17 04:41:54 +04:00
|
|
|
iter
|
|
|
|
ICodeParser::ParseString (iter begin, iter end, string **rval)
|
2000-10-12 11:55:13 +04:00
|
|
|
{
|
|
|
|
char delim = *begin;
|
|
|
|
bool isTerminated = false;
|
2000-10-13 03:58:51 +04:00
|
|
|
/* XXX not exactly exception safe, string may never get deleted */
|
2000-10-12 11:55:13 +04:00
|
|
|
string *str = new string();
|
2000-10-17 04:41:54 +04:00
|
|
|
*rval = 0;
|
2000-10-12 11:55:13 +04:00
|
|
|
|
2000-10-13 03:58:51 +04:00
|
|
|
if (delim != '\'' && delim != '"') {
|
2000-10-18 07:12:42 +04:00
|
|
|
NOT_REACHED ("|begin| does not point at a string");
|
2000-10-17 04:41:54 +04:00
|
|
|
delete str;
|
2000-10-13 03:58:51 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2000-10-12 11:55:13 +04:00
|
|
|
|
2000-10-13 03:58:51 +04:00
|
|
|
iter curpos = 0;
|
|
|
|
bool isEscaped = false;
|
|
|
|
for (curpos = ++begin; curpos < end; ++curpos) {
|
2000-10-12 11:55:13 +04:00
|
|
|
|
|
|
|
switch (*curpos) {
|
|
|
|
case '\\':
|
|
|
|
if (isEscaped) {
|
2000-10-13 03:58:51 +04:00
|
|
|
*str += '\\';
|
2000-10-12 11:55:13 +04:00
|
|
|
isEscaped = false;
|
|
|
|
} else {
|
|
|
|
isEscaped = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 't':
|
|
|
|
if (isEscaped) {
|
2000-10-13 03:58:51 +04:00
|
|
|
*str += '\t';
|
2000-10-12 11:55:13 +04:00
|
|
|
isEscaped = false;
|
|
|
|
} else {
|
2000-10-13 03:58:51 +04:00
|
|
|
*str += 't';
|
2000-10-12 11:55:13 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'n':
|
|
|
|
if (isEscaped) {
|
2000-10-13 03:58:51 +04:00
|
|
|
*str += '\n';
|
2000-10-12 11:55:13 +04:00
|
|
|
isEscaped = false;
|
|
|
|
} else {
|
2000-10-13 03:58:51 +04:00
|
|
|
*str += 'n';
|
2000-10-12 11:55:13 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'r':
|
|
|
|
if (isEscaped) {
|
2000-10-13 03:58:51 +04:00
|
|
|
*str += '\r';
|
2000-10-12 11:55:13 +04:00
|
|
|
isEscaped = false;
|
|
|
|
} else {
|
2000-10-13 03:58:51 +04:00
|
|
|
*str += 'r';
|
2000-10-12 11:55:13 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '\n':
|
|
|
|
if (isEscaped) {
|
2000-10-13 03:58:51 +04:00
|
|
|
*str += '\n';
|
2000-10-12 11:55:13 +04:00
|
|
|
isEscaped = false;
|
|
|
|
} else {
|
|
|
|
/* unescaped newline == unterminated string */
|
2000-10-13 03:58:51 +04:00
|
|
|
goto scan_done;
|
2000-10-12 11:55:13 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2000-10-13 03:58:51 +04:00
|
|
|
case '\'':
|
|
|
|
case '"':
|
|
|
|
if (*curpos == delim) {
|
|
|
|
if (isEscaped) {
|
|
|
|
*str += delim;
|
|
|
|
isEscaped = false;
|
|
|
|
} else {
|
|
|
|
++curpos;
|
|
|
|
isTerminated = true;
|
|
|
|
goto scan_done;
|
|
|
|
}
|
|
|
|
break;
|
2000-10-12 11:55:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
isEscaped = false;
|
2000-10-13 03:58:51 +04:00
|
|
|
*str += *curpos;
|
2000-10-12 11:55:13 +04:00
|
|
|
}
|
|
|
|
}
|
2000-10-13 03:58:51 +04:00
|
|
|
scan_done:
|
2000-10-12 11:55:13 +04:00
|
|
|
|
|
|
|
if (!isTerminated)
|
|
|
|
{
|
|
|
|
delete str;
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Unterminated string literal");
|
2000-10-12 11:55:13 +04:00
|
|
|
}
|
|
|
|
|
2000-10-17 04:41:54 +04:00
|
|
|
*rval = str;
|
2000-10-12 11:55:13 +04:00
|
|
|
return curpos;
|
|
|
|
}
|
|
|
|
|
2000-10-11 06:44:14 +04:00
|
|
|
iter
|
2000-10-13 03:58:51 +04:00
|
|
|
ICodeParser::ParseUInt32 (iter begin, iter end, uint32 *rval)
|
2000-10-11 06:44:14 +04:00
|
|
|
{
|
2000-10-13 03:58:51 +04:00
|
|
|
/* XXX add overflow checking */
|
2000-10-17 04:41:54 +04:00
|
|
|
*rval = 0;
|
|
|
|
int32 position = -1;
|
2000-10-13 03:58:51 +04:00
|
|
|
iter curpos;
|
|
|
|
|
|
|
|
for (curpos = begin; curpos < end; ++curpos) {
|
2000-10-11 06:44:14 +04:00
|
|
|
switch (*curpos)
|
|
|
|
{
|
|
|
|
case '0'...'9':
|
2000-10-13 03:58:51 +04:00
|
|
|
position++;
|
2000-10-11 06:44:14 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2000-10-13 03:58:51 +04:00
|
|
|
goto scan_done;
|
|
|
|
|
2000-10-11 06:44:14 +04:00
|
|
|
}
|
|
|
|
}
|
2000-10-13 03:58:51 +04:00
|
|
|
scan_done:
|
2000-10-11 06:44:14 +04:00
|
|
|
|
2000-10-14 04:06:42 +04:00
|
|
|
for (curpos = begin; position >= 0; --position)
|
2000-10-13 03:58:51 +04:00
|
|
|
*rval += (*curpos++ - '0') * static_cast<uint32>(pow (10, position));
|
|
|
|
|
|
|
|
return curpos;
|
2000-10-11 06:44:14 +04:00
|
|
|
}
|
|
|
|
|
2000-10-18 05:02:13 +04:00
|
|
|
/**********************************************************************
|
|
|
|
* operand parse functions (see comment in the .h file) ...
|
|
|
|
*/
|
2000-10-13 03:58:51 +04:00
|
|
|
|
|
|
|
iter
|
2000-10-18 07:12:42 +04:00
|
|
|
ICodeParser::ParseArgumentListOperand (iter begin, iter end,
|
|
|
|
VM::ArgumentList **rval)
|
2000-10-12 11:55:13 +04:00
|
|
|
{
|
2000-10-18 07:12:42 +04:00
|
|
|
/* parse argument list on the format "('argname': register[, ...])" */
|
|
|
|
TokenLocation tl = SeekTokenStart (begin, end);
|
|
|
|
VM::ArgumentList *al = new VM::ArgumentList();
|
|
|
|
|
|
|
|
if (tl.estimate != teOpenParen)
|
|
|
|
throw new ICodeParseException ("Expected Argument List");
|
|
|
|
|
|
|
|
tl = SeekTokenStart (tl.begin + 1, end);
|
|
|
|
while (tl.estimate == teString) {
|
|
|
|
/* look for the argname in quotes */
|
|
|
|
string *argName;
|
|
|
|
begin = ParseString (tl.begin, end, &argName);
|
|
|
|
|
|
|
|
/* look for the : */
|
|
|
|
tl = SeekTokenStart (begin, end);
|
|
|
|
if (tl.estimate != teColon)
|
|
|
|
throw new ICodeParseException ("Expected colon");
|
|
|
|
|
|
|
|
/* and now the register */
|
|
|
|
tl = SeekTokenStart (tl.begin + 1, end);
|
|
|
|
if (tl.estimate != teAlpha)
|
|
|
|
throw new ICodeParseException ("Expected Register value");
|
|
|
|
|
|
|
|
JSTypes::Register r;
|
|
|
|
begin = ParseRegister (tl.begin, end, &r);
|
|
|
|
/* pass 0 (null) as the "type" because it is
|
|
|
|
* not actually used by the interpreter, only in (the current)
|
|
|
|
* codegen (acording to rogerl.)
|
|
|
|
*/
|
|
|
|
VM::TypedRegister tr = VM::TypedRegister(r, 0);
|
|
|
|
VM::Argument arg = VM::Argument (tr, 0 /* XXX convert argName to a stringatom somehow */);
|
|
|
|
|
|
|
|
al->push_back(arg);
|
|
|
|
|
|
|
|
tl = SeekTokenStart (begin, end);
|
|
|
|
/* if the next token is a comma,
|
|
|
|
* seek to the next one and go again */
|
|
|
|
if (tl.estimate == teComma) {
|
|
|
|
tl = SeekTokenStart (tl.begin, end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tl.estimate != teCloseParen)
|
|
|
|
throw new ICodeParseException ("Expected close paren");
|
|
|
|
|
|
|
|
*rval = al;
|
|
|
|
|
|
|
|
return tl.begin + 1;
|
2000-10-12 11:55:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
iter
|
2000-10-18 05:02:13 +04:00
|
|
|
ICodeParser::ParseBinaryOpOperand (iter begin, iter end,
|
|
|
|
VM::BinaryOperator::BinaryOp *rval)
|
2000-10-12 11:55:13 +04:00
|
|
|
{
|
|
|
|
TokenLocation tl = SeekTokenStart (begin, end);
|
|
|
|
|
2000-10-18 05:02:13 +04:00
|
|
|
if (tl.estimate != teAlpha)
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Expected BinaryOp");
|
2000-10-12 11:55:13 +04:00
|
|
|
string *str;
|
2000-10-18 05:02:13 +04:00
|
|
|
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;
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Unknown BinaryOp");
|
2000-10-12 05:32:01 +04:00
|
|
|
}
|
2000-10-13 03:58:51 +04:00
|
|
|
|
|
|
|
iter
|
2000-10-18 05:02:13 +04:00
|
|
|
ICodeParser::ParseBoolOperand (iter begin, iter end, bool *rval)
|
2000-10-13 03:58:51 +04:00
|
|
|
{
|
|
|
|
TokenLocation tl = SeekTokenStart (begin, end);
|
|
|
|
|
|
|
|
if (tl.estimate != teAlpha)
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Expected boolean value");
|
2000-10-13 03:58:51 +04:00
|
|
|
|
2000-10-18 05:02:13 +04:00
|
|
|
return ParseBool (tl.begin, end, rval);
|
2000-10-13 03:58:51 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
iter
|
2000-10-18 05:02:13 +04:00
|
|
|
ICodeParser::ParseDoubleOperand (iter begin, iter end, double *rval)
|
2000-10-14 04:06:42 +04:00
|
|
|
{
|
2000-10-17 04:41:54 +04:00
|
|
|
TokenLocation tl = SeekTokenStart (begin, end);
|
|
|
|
|
|
|
|
if ((tl.estimate != teNumeric) && (tl.estimate != teMinus) &&
|
|
|
|
(tl.estimate != tePlus))
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Expected double value");
|
2000-10-17 04:41:54 +04:00
|
|
|
|
2000-10-18 05:02:13 +04:00
|
|
|
return ParseDouble (tl.begin, end, rval);
|
2000-10-14 04:06:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
iter
|
2000-10-18 05:02:13 +04:00
|
|
|
ICodeParser::ParseICodeModuleOperand (iter begin, iter end, string **rval)
|
2000-10-13 03:58:51 +04:00
|
|
|
{
|
|
|
|
TokenLocation tl = SeekTokenStart (begin, end);
|
|
|
|
|
|
|
|
if (tl.estimate != teString)
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Expected ICode Module as a quoted string");
|
2000-10-18 05:02:13 +04:00
|
|
|
return ParseString (tl.begin, end, rval);
|
2000-10-13 03:58:51 +04:00
|
|
|
}
|
|
|
|
|
2000-10-14 04:06:42 +04:00
|
|
|
iter
|
2000-10-18 05:02:13 +04:00
|
|
|
ICodeParser::ParseJSClassOperand (iter begin, iter end, string **rval)
|
2000-10-14 04:06:42 +04:00
|
|
|
{
|
2000-10-17 04:41:54 +04:00
|
|
|
TokenLocation tl = SeekTokenStart (begin, end);
|
|
|
|
|
|
|
|
if (tl.estimate != teString)
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Expected JSClass as a quoted string");
|
2000-10-18 05:02:13 +04:00
|
|
|
return ParseString (tl.begin, end, rval);
|
2000-10-14 04:06:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
iter
|
2000-10-18 05:02:13 +04:00
|
|
|
ICodeParser::ParseJSStringOperand (iter begin, iter end, string **rval)
|
2000-10-14 04:06:42 +04:00
|
|
|
{
|
2000-10-17 04:41:54 +04:00
|
|
|
TokenLocation tl = SeekTokenStart (begin, end);
|
|
|
|
|
|
|
|
if (tl.estimate != teString)
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Expected JSString as a quoted string");
|
2000-10-18 05:02:13 +04:00
|
|
|
return ParseString (tl.begin, end, rval);
|
2000-10-14 04:06:42 +04:00
|
|
|
}
|
2000-10-12 11:55:13 +04:00
|
|
|
|
2000-10-14 04:06:42 +04:00
|
|
|
iter
|
2000-10-18 05:02:13 +04:00
|
|
|
ICodeParser::ParseJSFunctionOperand (iter begin, iter end, string **rval)
|
2000-10-14 04:06:42 +04:00
|
|
|
{
|
2000-10-17 04:41:54 +04:00
|
|
|
TokenLocation tl = SeekTokenStart (begin, end);
|
|
|
|
|
|
|
|
if (tl.estimate != teString)
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Expected JSFunction as a quoted string");
|
2000-10-18 05:02:13 +04:00
|
|
|
return ParseString (tl.begin, end, rval);
|
2000-10-14 04:06:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
iter
|
2000-10-18 05:02:13 +04:00
|
|
|
ICodeParser::ParseJSTypeOperand (iter begin, iter end, string **rval)
|
2000-10-14 04:06:42 +04:00
|
|
|
{
|
2000-10-17 04:41:54 +04:00
|
|
|
TokenLocation tl = SeekTokenStart (begin, end);
|
|
|
|
|
|
|
|
if (tl.estimate != teString)
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Expected JSType as a quoted string");
|
2000-10-18 05:02:13 +04:00
|
|
|
return ParseString (tl.begin, end, rval);
|
2000-10-14 04:06:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
iter
|
2000-10-18 05:02:13 +04:00
|
|
|
ICodeParser::ParseLabelOperand (iter begin, iter end, VM::Label **rval)
|
2000-10-14 04:06:42 +04:00
|
|
|
{
|
2000-10-17 04:41:54 +04:00
|
|
|
TokenLocation tl = SeekTokenStart (begin, end);
|
|
|
|
|
|
|
|
if (tl.estimate != teAlpha)
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Expected Label Identifier or Offset keyword");
|
2000-10-17 04:41:54 +04:00
|
|
|
|
|
|
|
string *str;
|
|
|
|
begin = ParseAlpha (tl.begin, end, &str);
|
2000-10-17 12:02:16 +04:00
|
|
|
|
2000-10-18 05:02:13 +04:00
|
|
|
if (cmp_nocase(*str, keyword_offset, keyword_offset +
|
2000-10-17 04:41:54 +04:00
|
|
|
strlen(keyword_offset) + 1) == 0) {
|
2000-10-17 12:02:16 +04:00
|
|
|
/* got the "Offset" keyword, treat next thing as a jump offset
|
|
|
|
* expressed as "Offset +/-N" */
|
2000-10-17 04:41:54 +04:00
|
|
|
tl = SeekTokenStart (begin, end);
|
|
|
|
|
|
|
|
if ((tl.estimate != teNumeric) && (tl.estimate != teMinus) &&
|
|
|
|
(tl.estimate != tePlus))
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Expected numeric value after Offset keyword");
|
2000-10-17 12:02:16 +04:00
|
|
|
int32 ofs;
|
|
|
|
begin = ParseInt32 (tl.begin, end, &ofs);
|
2000-10-18 05:02:13 +04:00
|
|
|
VM::Label *new_label = new VM::Label(0);
|
|
|
|
new_label->mOffset = mStatementNodes.size() + ofs;
|
|
|
|
mUnnamedLabels.push_back (new_label);
|
|
|
|
*rval = new_label;
|
2000-10-17 04:41:54 +04:00
|
|
|
} else {
|
2000-10-17 12:02:16 +04:00
|
|
|
/* label expressed as "label_name", look for it in the
|
|
|
|
* namedlabels map */
|
2000-10-18 05:02:13 +04:00
|
|
|
LabelMap::const_iterator l = mNamedLabels.find(str->c_str());
|
|
|
|
if (l != mNamedLabels.end()) {
|
2000-10-17 12:02:16 +04:00
|
|
|
/* found the label, use it */
|
2000-10-18 05:02:13 +04:00
|
|
|
*rval = (*l).second;
|
2000-10-17 12:02:16 +04:00
|
|
|
} 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;
|
2000-10-18 05:02:13 +04:00
|
|
|
*rval = new_label;
|
|
|
|
mNamedLabels[str->c_str()] = new_label;
|
2000-10-17 12:02:16 +04:00
|
|
|
}
|
2000-10-17 04:41:54 +04:00
|
|
|
}
|
2000-10-17 12:02:16 +04:00
|
|
|
return begin;
|
2000-10-14 04:06:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
iter
|
2000-10-18 05:02:13 +04:00
|
|
|
ICodeParser::ParseUInt32Operand (iter begin, iter end, uint32 *rval)
|
2000-10-14 04:06:42 +04:00
|
|
|
{
|
2000-10-18 05:02:13 +04:00
|
|
|
TokenLocation tl = SeekTokenStart (begin, end);
|
|
|
|
|
|
|
|
if (tl.estimate != teNumeric)
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Expected UInt32 value");
|
2000-10-18 05:02:13 +04:00
|
|
|
|
|
|
|
return ParseUInt32 (tl.begin, end, rval);
|
2000-10-14 04:06:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
iter
|
2000-10-18 05:02:13 +04:00
|
|
|
ICodeParser::ParseRegisterOperand (iter begin, iter end,
|
|
|
|
JSTypes::Register *rval)
|
2000-10-14 04:06:42 +04:00
|
|
|
{
|
2000-10-18 05:02:13 +04:00
|
|
|
TokenLocation tl = SeekTokenStart (begin, end);
|
|
|
|
|
|
|
|
return ParseRegister (tl.begin, end, rval);
|
2000-10-14 04:06:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
iter
|
2000-10-18 05:02:13 +04:00
|
|
|
ICodeParser::ParseStringAtomOperand (iter begin, iter end, string **rval)
|
2000-10-14 04:06:42 +04:00
|
|
|
{
|
2000-10-18 05:02:13 +04:00
|
|
|
TokenLocation tl = SeekTokenStart (begin, end);
|
|
|
|
|
|
|
|
if (tl.estimate != teString)
|
2000-10-18 07:12:42 +04:00
|
|
|
throw new ICodeParseException ("Expected StringAtom as a quoted string");
|
2000-10-18 05:02:13 +04:00
|
|
|
return ParseString (tl.begin, end, rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* "High Level" parse functions ... */
|
|
|
|
iter ICodeParser::ParseInstruction (uint icodeID, iter begin, iter end)
|
|
|
|
{
|
|
|
|
iter curpos = begin;
|
|
|
|
StatementNode *node = new StatementNode();
|
|
|
|
node->begin = begin;
|
|
|
|
node->icodeID = icodeID;
|
|
|
|
|
2000-10-18 07:12:42 +04:00
|
|
|
fprintf (stderr, "parsing instruction %s\n", icodemap[icodeID].name);
|
|
|
|
|
2000-10-18 05:02:13 +04:00
|
|
|
/* add the node now, so the parse*operand functions can see it */
|
|
|
|
mStatementNodes.push_back (node);
|
|
|
|
|
|
|
|
# define CASE_TYPE(T, C, CTYPE) \
|
|
|
|
case ot##T: \
|
|
|
|
{ \
|
|
|
|
C rval; \
|
2000-10-18 07:12:42 +04:00
|
|
|
fprintf (stderr, "parsing operand type %u\n", \
|
|
|
|
static_cast<uint32>(ot##T)); \
|
2000-10-18 05:02:13 +04:00
|
|
|
node->operand[i].type = ot##T; \
|
|
|
|
curpos = Parse##T##Operand (curpos, end, &rval); \
|
|
|
|
node->operand[i].data = CTYPE<int64>(rval); \
|
|
|
|
break; \
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint i = 0; i < 4; ++i)
|
|
|
|
{
|
|
|
|
switch (icodemap[icodeID].otype[i])
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2000-10-18 07:12:42 +04:00
|
|
|
if (i != 3 && icodemap[icodeID].otype[i + 1] != otNone) {
|
|
|
|
TokenLocation tl = SeekTokenStart (curpos, end);
|
|
|
|
if (tl.estimate != teComma)
|
|
|
|
throw new ICodeParseException ("Expected comma");
|
|
|
|
tl = SeekTokenStart (tl.begin + 1, end);
|
|
|
|
curpos = tl.begin;
|
|
|
|
}
|
2000-10-18 05:02:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
# undef CASE_TYPE
|
|
|
|
|
|
|
|
return curpos;
|
|
|
|
}
|
|
|
|
|
|
|
|
iter
|
|
|
|
ICodeParser::ParseStatement (iter begin, iter end)
|
|
|
|
{
|
|
|
|
bool isLabel = false;
|
|
|
|
iter firstTokenEnd = end;
|
|
|
|
TokenLocation tl = SeekTokenStart (begin, end);
|
|
|
|
|
|
|
|
if (tl.estimate != teAlpha)
|
|
|
|
throw new ICodeParseException ("Expected an alphanumeric token (like maybe an instruction or a label.)");
|
|
|
|
|
|
|
|
for (iter curpos = tl.begin; curpos < end; ++curpos) {
|
|
|
|
switch (*curpos)
|
|
|
|
{
|
|
|
|
case ':':
|
|
|
|
isLabel = true;
|
|
|
|
firstTokenEnd = ++curpos;
|
|
|
|
goto scan_done;
|
|
|
|
|
|
|
|
case 'a'...'z':
|
|
|
|
case 'A'...'Z':
|
|
|
|
case '0'...'9':
|
|
|
|
case '_':
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
firstTokenEnd = curpos;
|
|
|
|
goto scan_done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
scan_done:
|
|
|
|
|
|
|
|
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] +
|
2000-10-18 07:12:42 +04:00
|
|
|
strlen(icodemap[i].name) + 1) == 0)
|
2000-10-18 05:02:13 +04:00
|
|
|
/* if match found, parse it's operands */
|
|
|
|
return ParseInstruction (i, firstTokenEnd, end);
|
|
|
|
/* otherwise, choke on it */
|
|
|
|
throw new ICodeParseException ("Unknown ICode " + icode_str);
|
|
|
|
}
|
|
|
|
|
2000-10-14 04:06:42 +04:00
|
|
|
}
|
|
|
|
|
2000-10-11 06:44:14 +04:00
|
|
|
}
|
|
|
|
}
|