Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
magicseteditor
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
magicseteditor
Commits
7ce6b2c6
Commit
7ce6b2c6
authored
Apr 05, 2011
by
twanvl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
warn about functions ending with a statement instead of a return value
parent
7104e9a7
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
220 additions
and
203 deletions
+220
-203
src/script/parser.cpp
src/script/parser.cpp
+220
-203
No files found.
src/script/parser.cpp
View file @
7ce6b2c6
...
@@ -373,13 +373,23 @@ enum Precedence
...
@@ -373,13 +373,23 @@ enum Precedence
,
PREC_NONE
,
PREC_NONE
};
};
enum
ExprType
{
EXPR_VAR
// A single variable, which could be converted to the left hand side of an assignment
,
EXPR_STATEMENT
// A 'statement', i.e. an expression that shouldn't be the last one
,
EXPR_OTHER
,
EXPR_FAILED
};
/// Parse an expression
/// Parse an expression
/** @param input Read tokens from the input
/** @param input Read tokens from the input
* @param scrip Add resulting instructions to the script
* @param scrip Add resulting instructions to the script
* @param min_prec Minimum precedence level for operators
* @param min_prec Minimum precedence level for operators
*
* @returns the type of expression
*
* NOTE: The net stack effect of an expression should be +1
* NOTE: The net stack effect of an expression should be +1
*/
*/
void
parseExpr
(
TokenIterator
&
input
,
Script
&
script
,
Precedence
min_prec
);
ExprType
parseExpr
(
TokenIterator
&
input
,
Script
&
script
,
Precedence
min_prec
);
/// Parse an expression, possibly with operators applied. Optionally adds an instruction at the end.
/// Parse an expression, possibly with operators applied. Optionally adds an instruction at the end.
/** @param input Read tokens from the input
/** @param input Read tokens from the input
...
@@ -389,7 +399,7 @@ void parseExpr(TokenIterator& input, Script& script, Precedence min_prec);
...
@@ -389,7 +399,7 @@ void parseExpr(TokenIterator& input, Script& script, Precedence min_prec);
* @param close_with_data Data for the instruction at the end
* @param close_with_data Data for the instruction at the end
* NOTE: The net stack effect of an expression should be +1
* NOTE: The net stack effect of an expression should be +1
*/
*/
void
parseOper
(
TokenIterator
&
input
,
Script
&
script
,
Precedence
min_prec
,
InstructionType
close_with
=
I_NOP
,
int
close_with_data
=
0
);
ExprType
parseOper
(
TokenIterator
&
input
,
Script
&
script
,
Precedence
min_prec
,
InstructionType
close_with
=
I_NOP
,
int
close_with_data
=
0
);
/// Parse call arguments, "(...)"
/// Parse call arguments, "(...)"
void
parseCallArguments
(
TokenIterator
&
input
,
Script
&
script
,
vector
<
Variable
>&
arguments
);
void
parseCallArguments
(
TokenIterator
&
input
,
Script
&
script
,
vector
<
Variable
>&
arguments
);
...
@@ -434,217 +444,220 @@ bool expectToken(TokenIterator& input, const Char* expect, const Token* opening
...
@@ -434,217 +444,220 @@ bool expectToken(TokenIterator& input, const Char* expect, const Token* opening
}
}
}
}
void
parseExpr
(
TokenIterator
&
input
,
Script
&
script
,
Precedence
minPrec
)
{
ExprType
parseExpr
(
TokenIterator
&
input
,
Script
&
script
,
Precedence
minPrec
)
{
// usually loop only once, unless we encounter newlines
Token
token
=
input
.
read
();
while
(
true
)
{
if
(
token
==
_
(
"("
))
{
Token
token
=
input
.
read
();
// Parentheses = grouping for precedence of expressions
if
(
token
==
_
(
"("
))
{
parseOper
(
input
,
script
,
PREC_ALL
);
// Parentheses = grouping for precedence of expressions
expectToken
(
input
,
_
(
")"
),
&
token
);
parseOper
(
input
,
script
,
PREC_ALL
);
}
else
if
(
token
==
_
(
"{"
))
{
expectToken
(
input
,
_
(
")"
),
&
token
);
// {} = function block. Parse a new Script
}
else
if
(
token
==
_
(
"{"
))
{
intrusive_ptr
<
Script
>
subScript
(
new
Script
);
// {} = function block. Parse a new Script
ExprType
t
=
parseOper
(
input
,
*
subScript
,
PREC_ALL
);
intrusive_ptr
<
Script
>
subScript
(
new
Script
);
if
(
t
==
EXPR_STATEMENT
)
{
parseOper
(
input
,
*
subScript
,
PREC_ALL
);
input
.
add_error
(
_
(
"Warning: last statement of a function should be an expression, i.e. it should return a result in all cases."
));
expectToken
(
input
,
_
(
"}"
),
&
token
);
}
script
.
addInstruction
(
I_PUSH_CONST
,
subScript
);
expectToken
(
input
,
_
(
"}"
),
&
token
);
}
else
if
(
token
==
_
(
"["
))
{
script
.
addInstruction
(
I_PUSH_CONST
,
subScript
);
// [] = list or map literal
}
else
if
(
token
==
_
(
"["
))
{
unsigned
int
count
=
0
;
// [] = list or map literal
Token
t
=
input
.
peek
();
unsigned
int
count
=
0
;
while
(
t
!=
_
(
"]"
)
&&
t
!=
TOK_EOF
)
{
Token
t
=
input
.
peek
();
if
(
input
.
peek
(
2
)
==
_
(
":"
)
&&
(
t
.
type
==
TOK_NAME
||
t
.
type
==
TOK_INT
||
t
.
type
==
TOK_STRING
))
{
while
(
t
!=
_
(
"]"
)
&&
t
!=
TOK_EOF
)
{
// name: ...
if
(
input
.
peek
(
2
)
==
_
(
":"
)
&&
(
t
.
type
==
TOK_NAME
||
t
.
type
==
TOK_INT
||
t
.
type
==
TOK_STRING
))
{
script
.
addInstruction
(
I_PUSH_CONST
,
to_script
(
t
.
value
));
// name: ...
input
.
read
();
// skip the name
script
.
addInstruction
(
I_PUSH_CONST
,
to_script
(
t
.
value
));
input
.
read
();
// and the :
input
.
read
();
// skip the name
}
else
{
input
.
read
();
// and the :
// implicit numbered element
}
else
{
script
.
addInstruction
(
I_PUSH_CONST
,
script_nil
);
// implicit numbered element
}
script
.
addInstruction
(
I_PUSH_CONST
,
script_nil
);
parseOper
(
input
,
script
,
PREC_AND
);
}
++
count
;
parseOper
(
input
,
script
,
PREC_AND
);
++
count
;
t
=
input
.
peek
();
if
(
t
==
_
(
","
))
{
// Comma separating the elements
input
.
read
();
t
=
input
.
peek
();
t
=
input
.
peek
();
if
(
t
==
_
(
","
))
{
// Comma separating the elements
input
.
read
();
t
=
input
.
peek
();
}
}
}
expectToken
(
input
,
_
(
"]"
),
&
token
);
}
script
.
addInstruction
(
I_MAKE_OBJECT
,
count
);
expectToken
(
input
,
_
(
"]"
),
&
token
);
}
else
if
(
minPrec
<=
PREC_UNARY
&&
token
==
_
(
"-"
))
{
script
.
addInstruction
(
I_MAKE_OBJECT
,
count
);
parseOper
(
input
,
script
,
PREC_UNARY
,
I_UNARY
,
I_NEGATE
);
// unary negation
}
else
if
(
minPrec
<=
PREC_UNARY
&&
token
==
_
(
"-"
))
{
}
else
if
(
token
==
TOK_NAME
)
{
parseOper
(
input
,
script
,
PREC_UNARY
,
I_UNARY
,
I_NEGATE
);
// unary negation
if
(
minPrec
<=
PREC_UNARY
&&
token
==
_
(
"not"
))
{
}
else
if
(
token
==
TOK_NAME
)
{
parseOper
(
input
,
script
,
PREC_UNARY
,
I_UNARY
,
I_NOT
);
// unary not
if
(
minPrec
<=
PREC_UNARY
&&
token
==
_
(
"not"
))
{
}
else
if
(
token
==
_
(
"true"
))
{
parseOper
(
input
,
script
,
PREC_UNARY
,
I_UNARY
,
I_NOT
);
// unary not
script
.
addInstruction
(
I_PUSH_CONST
,
script_true
);
// boolean constant : true
}
else
if
(
token
==
_
(
"true"
))
{
}
else
if
(
token
==
_
(
"false"
))
{
script
.
addInstruction
(
I_PUSH_CONST
,
script_true
);
// boolean constant : true
script
.
addInstruction
(
I_PUSH_CONST
,
script_false
);
// boolean constant : false
}
else
if
(
token
==
_
(
"false"
))
{
}
else
if
(
token
==
_
(
"nil"
))
{
script
.
addInstruction
(
I_PUSH_CONST
,
script_false
);
// boolean constant : false
script
.
addInstruction
(
I_PUSH_CONST
,
script_nil
);
// universal constant : nil
}
else
if
(
token
==
_
(
"nil"
))
{
}
else
if
(
token
==
_
(
"if"
))
{
script
.
addInstruction
(
I_PUSH_CONST
,
script_nil
);
// universal constant : nil
// if AAA then BBB else CCC
}
else
if
(
token
==
_
(
"if"
))
{
parseOper
(
input
,
script
,
PREC_AND
);
// AAA
// if AAA then BBB else CCC
unsigned
jmpElse
=
script
.
addInstruction
(
I_JUMP_IF_NOT
);
// jnz lbl_else
parseOper
(
input
,
script
,
PREC_AND
);
// AAA
expectToken
(
input
,
_
(
"then"
));
// then
unsigned
jmpElse
=
script
.
addInstruction
(
I_JUMP_IF_NOT
);
// jnz lbl_else
parseOper
(
input
,
script
,
PREC_SET
);
// BBB
expectToken
(
input
,
_
(
"then"
));
// then
unsigned
jmpEnd
=
script
.
addInstruction
(
I_JUMP
);
// jump lbl_end
parseOper
(
input
,
script
,
PREC_SET
);
// BBB
script
.
comeFrom
(
jmpElse
);
// lbl_else:
unsigned
jmpEnd
=
script
.
addInstruction
(
I_JUMP
);
// jump lbl_end
if
(
input
.
peek
()
==
_
(
"else"
))
{
//else
script
.
comeFrom
(
jmpElse
);
// lbl_else:
input
.
read
();
bool
has_else
=
input
.
peek
()
==
_
(
"else"
);
//else
parseOper
(
input
,
script
,
PREC_SET
);
// CCC
if
(
has_else
)
{
}
else
{
input
.
read
();
script
.
addInstruction
(
I_PUSH_CONST
,
script_nil
);
parseOper
(
input
,
script
,
PREC_SET
);
// CCC
}
}
else
{
script
.
comeFrom
(
jmpEnd
);
// lbl_end:
script
.
addInstruction
(
I_PUSH_CONST
,
script_nil
);
}
else
if
(
token
==
_
(
"for"
))
{
}
// the loop body should have a net stack effect of 0, but the entire expression of +1
script
.
comeFrom
(
jmpEnd
);
// lbl_end:
// solution: add all results from the body, start with nil
return
has_else
?
EXPR_OTHER
:
EXPR_STATEMENT
;
bool
is_each
=
input
.
peek
()
==
_
(
"each"
);
}
else
if
(
token
==
_
(
"for"
))
{
if
(
is_each
)
{
// the loop body should have a net stack effect of 0, but the entire expression of +1
// for each AAA(:BBB) in CCC do EEE
// solution: add all results from the body, start with nil
input
.
read
();
// each?
bool
is_each
=
input
.
peek
()
==
_
(
"each"
);
}
else
{
if
(
is_each
)
{
// for AAA(:BBB) from CCC to DDD do EEE
// for each AAA(:BBB) in CCC do EEE
}
input
.
read
();
// each?
// name
}
else
{
Token
name
=
input
.
read
();
// AAA
// for AAA(:BBB) from CCC to DDD do EEE
}
// name
Token
name
=
input
.
read
();
// AAA
if
(
name
!=
TOK_NAME
)
{
input
.
expected
(
_
(
"name"
));
}
Variable
var
=
string_to_variable
(
name
.
value
);
// key:value?
bool
with_key
=
input
.
peek
()
==
_
(
":"
);
Variable
key
=
(
Variable
)
-
1
;
if
(
with_key
)
{
input
.
read
();
// :
name
=
input
.
read
();
// BBB
if
(
name
!=
TOK_NAME
)
{
if
(
name
!=
TOK_NAME
)
{
input
.
expected
(
_
(
"name"
));
input
.
expected
(
_
(
"name"
));
}
}
Variable
var
=
string_to_variable
(
name
.
value
);
key
=
string_to_variable
(
name
.
value
);
// key:value?
swap
(
var
,
key
);
bool
with_key
=
input
.
peek
()
==
_
(
":"
);
}
Variable
key
=
(
Variable
)
-
1
;
// iterator
if
(
with_key
)
{
if
(
is_each
)
{
input
.
read
();
// :
expectToken
(
input
,
_
(
"in"
));
// in
name
=
input
.
read
();
// BBB
parseOper
(
input
,
script
,
PREC_AND
);
// CCC
if
(
name
!=
TOK_NAME
)
{
script
.
addInstruction
(
I_UNARY
,
I_ITERATOR_C
);
// iterator_collection
input
.
expected
(
_
(
"name"
));
}
else
{
}
expectToken
(
input
,
_
(
"from"
));
// from
key
=
string_to_variable
(
name
.
value
);
parseOper
(
input
,
script
,
PREC_AND
);
// CCC
swap
(
var
,
key
);
expectToken
(
input
,
_
(
"to"
));
// to
}
parseOper
(
input
,
script
,
PREC_AND
);
// DDD
// iterator
script
.
addInstruction
(
I_BINARY
,
I_ITERATOR_R
);
// iterator_range
if
(
is_each
)
{
}
expectToken
(
input
,
_
(
"in"
));
// in
script
.
addInstruction
(
I_PUSH_CONST
,
script_nil
);
// push nil
parseOper
(
input
,
script
,
PREC_AND
);
// CCC
unsigned
lblStart
=
script
.
addInstruction
(
with_key
script
.
addInstruction
(
I_UNARY
,
I_ITERATOR_C
);
// iterator_collection
?
I_LOOP_WITH_KEY
// lbl_start: loop_with_key lbl_end
}
else
{
:
I_LOOP
);
// lbl_start: loop lbl_end
expectToken
(
input
,
_
(
"from"
));
// from
expectToken
(
input
,
_
(
"do"
));
// do
parseOper
(
input
,
script
,
PREC_AND
);
// CCC
if
(
with_key
)
{
expectToken
(
input
,
_
(
"to"
));
// to
script
.
addInstruction
(
I_SET_VAR
,
key
);
// set key_name
parseOper
(
input
,
script
,
PREC_AND
);
// DDD
script
.
addInstruction
(
I_POP
);
// pop
script
.
addInstruction
(
I_BINARY
,
I_ITERATOR_R
);
// iterator_range
}
}
script
.
addInstruction
(
I_SET_VAR
,
var
);
// set name
script
.
addInstruction
(
I_PUSH_CONST
,
script_nil
);
// push nil
script
.
addInstruction
(
I_POP
);
// pop
unsigned
lblStart
=
script
.
addInstruction
(
with_key
parseOper
(
input
,
script
,
PREC_SET
,
I_BINARY
,
I_ADD
);
// EEE; add
?
I_LOOP_WITH_KEY
// lbl_start: loop_with_key lbl_end
script
.
addInstruction
(
I_JUMP
,
lblStart
);
// jump lbl_start
:
I_LOOP
);
// lbl_start: loop lbl_end
script
.
comeFrom
(
lblStart
);
// lbl_end:
expectToken
(
input
,
_
(
"do"
));
// do
}
else
if
(
token
==
_
(
"rgb"
))
{
if
(
with_key
)
{
// rgb(r, g, b)
script
.
addInstruction
(
I_SET_VAR
,
key
);
// set key_name
expectToken
(
input
,
_
(
"("
));
script
.
addInstruction
(
I_POP
);
// pop
parseOper
(
input
,
script
,
PREC_ALL
);
// r
}
expectToken
(
input
,
_
(
","
));
script
.
addInstruction
(
I_SET_VAR
,
var
);
// set name
parseOper
(
input
,
script
,
PREC_ALL
);
// g
script
.
addInstruction
(
I_POP
);
// pop
expectToken
(
input
,
_
(
","
));
parseOper
(
input
,
script
,
PREC_SET
,
I_BINARY
,
I_ADD
);
// EEE; add
parseOper
(
input
,
script
,
PREC_ALL
);
// b
script
.
addInstruction
(
I_JUMP
,
lblStart
);
// jump lbl_start
expectToken
(
input
,
_
(
")"
));
script
.
comeFrom
(
lblStart
);
// lbl_end:
script
.
addInstruction
(
I_TERNARY
,
I_RGB
);
}
else
if
(
token
==
_
(
"rgb
"
))
{
}
else
if
(
token
==
_
(
"rgba
"
))
{
// rgb(r, g, b
)
// rgba(r, g, b, a
)
expectToken
(
input
,
_
(
"("
));
expectToken
(
input
,
_
(
"("
));
parseOper
(
input
,
script
,
PREC_ALL
);
// r
parseOper
(
input
,
script
,
PREC_ALL
);
// r
expectToken
(
input
,
_
(
","
));
expectToken
(
input
,
_
(
","
));
parseOper
(
input
,
script
,
PREC_ALL
);
// g
parseOper
(
input
,
script
,
PREC_ALL
);
// g
expectToken
(
input
,
_
(
","
));
expectToken
(
input
,
_
(
","
));
parseOper
(
input
,
script
,
PREC_ALL
);
// b
parseOper
(
input
,
script
,
PREC_ALL
);
// b
expectToken
(
input
,
_
(
")
"
));
expectToken
(
input
,
_
(
",
"
));
script
.
addInstruction
(
I_TERNARY
,
I_RGB
);
parseOper
(
input
,
script
,
PREC_ALL
);
// a
}
else
if
(
token
==
_
(
"rgba"
))
{
expectToken
(
input
,
_
(
")"
));
// rgba(r, g, b, a)
script
.
addInstruction
(
I_QUATERNARY
,
I_RGBA
);
expectToken
(
input
,
_
(
"("
));
}
else
if
(
token
==
_
(
"min"
)
||
token
==
_
(
"max"
))
{
parseOper
(
input
,
script
,
PREC_ALL
);
// r
// min(x,y,z,...)
expectToken
(
input
,
_
(
","
))
;
unsigned
int
op
=
token
==
_
(
"min"
)
?
I_MIN
:
I_MAX
;
parseOper
(
input
,
script
,
PREC_ALL
);
// g
expectToken
(
input
,
_
(
"("
));
expectToken
(
input
,
_
(
","
));
parseOper
(
input
,
script
,
PREC_ALL
);
// first
parseOper
(
input
,
script
,
PREC_ALL
);
// b
while
(
input
.
peek
()
==
_
(
","
))
{
expectToken
(
input
,
_
(
","
));
expectToken
(
input
,
_
(
","
));
parseOper
(
input
,
script
,
PREC_ALL
);
// a
parseOper
(
input
,
script
,
PREC_ALL
);
// second, third, etc.
expectToken
(
input
,
_
(
")"
));
script
.
addInstruction
(
I_BINARY
,
op
);
script
.
addInstruction
(
I_QUATERNARY
,
I_RGBA
);
}
}
else
if
(
token
==
_
(
"min"
)
||
token
==
_
(
"max"
))
{
expectToken
(
input
,
_
(
")"
),
&
token
);
// min(x,y,z,...)
}
else
if
(
token
==
_
(
"assert"
))
{
unsigned
int
op
=
token
==
_
(
"min"
)
?
I_MIN
:
I_MAX
;
// assert(condition)
expectToken
(
input
,
_
(
"("
));
expectToken
(
input
,
_
(
"("
));
parseOper
(
input
,
script
,
PREC_ALL
);
// first
size_t
start
=
input
.
peek
().
pos
;
while
(
input
.
peek
()
==
_
(
","
))
{
int
line
=
input
.
getLineNumber
();
expectToken
(
input
,
_
(
","
));
size_t
function_pos
=
script
.
getConstants
().
size
();
parseOper
(
input
,
script
,
PREC_ALL
);
// second, third, etc.
script
.
addInstruction
(
I_PUSH_CONST
,
script_warning
);
script
.
addInstruction
(
I_BINARY
,
op
);
parseOper
(
input
,
script
,
PREC_ALL
);
// condition
}
size_t
end
=
input
.
peek
().
pos
;
expectToken
(
input
,
_
(
")"
),
&
token
);
String
message
=
String
::
Format
(
_
(
"Assertion failure on line %d:
\n
expected: "
),
line
)
+
input
.
getSourceCode
(
start
,
end
);
}
else
if
(
token
==
_
(
"assert"
))
{
expectToken
(
input
,
_
(
")"
),
&
token
);
// assert(condition)
if
(
script
.
getInstructions
().
back
().
instr
==
I_BINARY
&&
script
.
getInstructions
().
back
().
instr2
==
I_EQ
)
{
expectToken
(
input
,
_
(
"("
));
// compile "assert(x == y)" into
size_t
start
=
input
.
peek
().
pos
;
// warning_if_neq("condition", _1: x, _2: y)
int
line
=
input
.
getLineNumber
();
message
+=
_
(
"
\n
found: "
);
size_t
function_pos
=
script
.
getConstants
().
size
();
script
.
getConstants
()[
function_pos
]
=
script_warning_if_neq
;
script
.
addInstruction
(
I_PUSH_CONST
,
script_warning
);
script
.
getInstructions
().
pop_back
();
// POP == instruction
parseOper
(
input
,
script
,
PREC_ALL
);
// condition
script
.
addInstruction
(
I_PUSH_CONST
,
message
);
// push "condition"
size_t
end
=
input
.
peek
().
pos
;
script
.
addInstruction
(
I_CALL
,
3
);
// call
String
message
=
String
::
Format
(
_
(
"Assertion failure on line %d:
\n
expected: "
),
line
)
+
input
.
getSourceCode
(
start
,
end
);
script
.
addInstruction
(
I_NOP
,
SCRIPT_VAR__1
);
// (_1:)
expectToken
(
input
,
_
(
")"
),
&
token
);
script
.
addInstruction
(
I_NOP
,
SCRIPT_VAR__2
);
// (_2:)
if
(
script
.
getInstructions
().
back
().
instr
==
I_BINARY
&&
script
.
getInstructions
().
back
().
instr2
==
I_EQ
)
{
script
.
addInstruction
(
I_NOP
,
SCRIPT_VAR_input
);
// (input:)
// compile "assert(x == y)" into
// warning_if_neq("condition", _1: x, _2: y)
message
+=
_
(
"
\n
found: "
);
script
.
getConstants
()[
function_pos
]
=
script_warning_if_neq
;
script
.
getInstructions
().
pop_back
();
// POP == instruction
script
.
addInstruction
(
I_PUSH_CONST
,
message
);
// push "condition"
script
.
addInstruction
(
I_CALL
,
3
);
// call
script
.
addInstruction
(
I_NOP
,
SCRIPT_VAR__1
);
// (_1:)
script
.
addInstruction
(
I_NOP
,
SCRIPT_VAR__2
);
// (_2:)
script
.
addInstruction
(
I_NOP
,
SCRIPT_VAR_input
);
// (input:)
}
else
{
// compile into: warning("condition", condition: not condition)
script
.
addInstruction
(
I_UNARY
,
I_NOT
);
// not
script
.
addInstruction
(
I_PUSH_CONST
,
message
);
// push "condition"
script
.
addInstruction
(
I_CALL
,
2
);
// call
script
.
addInstruction
(
I_NOP
,
SCRIPT_VAR_condition
);
// (condition:)
script
.
addInstruction
(
I_NOP
,
SCRIPT_VAR_input
);
// (input:)
}
}
else
{
}
else
{
// variable
// compile into: warning("condition", condition: not condition)
Variable
var
=
string_to_variable
(
token
.
value
);
script
.
addInstruction
(
I_UNARY
,
I_NOT
);
// not
script
.
addInstruction
(
I_GET_VAR
,
var
);
script
.
addInstruction
(
I_PUSH_CONST
,
message
);
// push "condition"
script
.
addInstruction
(
I_CALL
,
2
);
// call
script
.
addInstruction
(
I_NOP
,
SCRIPT_VAR_condition
);
// (condition:)
script
.
addInstruction
(
I_NOP
,
SCRIPT_VAR_input
);
// (input:)
}
}
}
else
if
(
token
==
TOK_INT
)
{
return
EXPR_STATEMENT
;
long
l
=
0
;
//l = lexical_cast<long>(token.value);
token
.
value
.
ToLong
(
&
l
);
script
.
addInstruction
(
I_PUSH_CONST
,
to_script
(
l
));
}
else
if
(
token
==
TOK_DOUBLE
)
{
double
d
=
0
;
//d = lexical_cast<double>(token.value);
token
.
value
.
ToDouble
(
&
d
);
script
.
addInstruction
(
I_PUSH_CONST
,
to_script
(
d
));
}
else
if
(
token
==
TOK_STRING
)
{
script
.
addInstruction
(
I_PUSH_CONST
,
to_script
(
token
.
value
));
}
else
{
}
else
{
input
.
expected
(
_
(
"expression"
));
// variable
return
;
Variable
var
=
string_to_variable
(
token
.
value
);
script
.
addInstruction
(
I_GET_VAR
,
var
);
return
EXPR_VAR
;
}
}
break
;
}
else
if
(
token
==
TOK_INT
)
{
long
l
=
0
;
//l = lexical_cast<long>(token.value);
token
.
value
.
ToLong
(
&
l
);
script
.
addInstruction
(
I_PUSH_CONST
,
to_script
(
l
));
}
else
if
(
token
==
TOK_DOUBLE
)
{
double
d
=
0
;
//d = lexical_cast<double>(token.value);
token
.
value
.
ToDouble
(
&
d
);
script
.
addInstruction
(
I_PUSH_CONST
,
to_script
(
d
));
}
else
if
(
token
==
TOK_STRING
)
{
script
.
addInstruction
(
I_PUSH_CONST
,
to_script
(
token
.
value
));
}
else
{
script
.
addInstruction
(
I_PUSH_CONST
,
script_nil
);
input
.
expected
(
_
(
"expression"
));
return
EXPR_FAILED
;
}
}
return
EXPR_OTHER
;
}
}
void
parseOper
(
TokenIterator
&
input
,
Script
&
script
,
Precedence
minPrec
,
InstructionType
closeWith
,
int
closeWithData
)
{
ExprType
parseOper
(
TokenIterator
&
input
,
Script
&
script
,
Precedence
minPrec
,
InstructionType
closeWith
,
int
closeWithData
)
{
size_t
added
=
script
.
getInstructions
().
size
();
// number of instructions added
ExprType
type
=
parseExpr
(
input
,
script
,
minPrec
);
// first argument
parseExpr
(
input
,
script
,
minPrec
);
// first argument
added
=
script
.
getInstructions
().
size
()
-
added
;
// read any operators after an expression
// read any operators after an expression
// EBNF: expr = expr | expr oper expr
// EBNF: expr = expr | expr oper expr
// without left recursion: expr = expr (oper expr)*
// without left recursion: expr = expr (oper expr)*
...
@@ -656,6 +669,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
...
@@ -656,6 +669,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
input
.
putBack
();
input
.
putBack
();
break
;
break
;
}
}
if
(
minPrec
<=
PREC_SEQ
&&
token
==
_
(
";"
))
{
if
(
minPrec
<=
PREC_SEQ
&&
token
==
_
(
";"
))
{
Token
next
=
input
.
peek
(
1
);
Token
next
=
input
.
peek
(
1
);
if
(
next
==
TOK_RPAREN
||
next
==
TOK_EOF
)
{
if
(
next
==
TOK_RPAREN
||
next
==
TOK_EOF
)
{
...
@@ -663,12 +677,12 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
...
@@ -663,12 +677,12 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
break
;
break
;
}
}
script
.
addInstruction
(
I_POP
);
// discard result of first expression
script
.
addInstruction
(
I_POP
);
// discard result of first expression
parseOper
(
input
,
script
,
PREC_SET
);
type
=
parseOper
(
input
,
script
,
PREC_SET
);
}
else
if
(
minPrec
<=
PREC_SET
&&
token
==
_
(
":="
))
{
}
else
if
(
minPrec
<=
PREC_SET
&&
token
==
_
(
":="
))
{
// We made a mistake, the part before the := should be a variable name,
// We made a mistake, the part before the := should be a variable name,
// not an expression. Remove that instruction.
// not an expression. Remove that instruction.
Instruction
&
instr
=
script
.
getInstructions
().
back
();
Instruction
&
instr
=
script
.
getInstructions
().
back
();
if
(
added
!=
1
||
instr
.
instr
!=
I_GET_VAR
)
{
if
(
type
!=
EXPR_VAR
||
instr
.
instr
!=
I_GET_VAR
)
{
input
.
add_error
(
_
(
"Can only assign to variables"
));
input
.
add_error
(
_
(
"Can only assign to variables"
));
}
}
script
.
getInstructions
().
pop_back
();
script
.
getInstructions
().
pop_back
();
...
@@ -790,16 +804,19 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
...
@@ -790,16 +804,19 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
// only if we don't match another token!
// only if we don't match another token!
input
.
putBack
();
input
.
putBack
();
script
.
addInstruction
(
I_POP
);
script
.
addInstruction
(
I_POP
);
parseOper
(
input
,
script
,
PREC_SET
);
type
=
parseOper
(
input
,
script
,
PREC_SET
);
}
else
{
}
else
{
input
.
putBack
();
input
.
putBack
();
break
;
break
;
}
}
if
(
type
==
EXPR_VAR
)
type
=
EXPR_OTHER
;
// var only applies to single variables, not to things with operators
}
}
// add closing instruction
// add closing instruction
if
(
closeWith
!=
I_NOP
)
{
if
(
closeWith
!=
I_NOP
)
{
script
.
addInstruction
(
closeWith
,
closeWithData
);
script
.
addInstruction
(
closeWith
,
closeWithData
);
}
}
return
type
;
}
}
void
parseCallArguments
(
TokenIterator
&
input
,
Script
&
script
,
vector
<
Variable
>&
arguments
)
{
void
parseCallArguments
(
TokenIterator
&
input
,
Script
&
script
,
vector
<
Variable
>&
arguments
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment