LOC_CONV_TRY_1,
LOC_ITEM_FORCE_ERROR_1,
LOC_UNARY_CHECK_4, // 11025
+ LOC_IF_CHECK_1,
+ LOC_IF_CHECK_2,
+ LOC_FORC_CHECK_1,
+ LOC_FORC_CHECK_2,
+ LOC_FORC_CHECK_3, // 11030
+ LOC_ITEM_AS_INT_1,
+ LOC_ITEM_AS_INT_2,
+ LOC_METHOD_CALL_CHECK_1,
LOC_COUNT
};
{
}
+/**
+ * @brief Checks a calculable node for correctness.
+ *
+ * @param description description of the meaning, e.g. "start value"
+ * @param expectedClass the node must have this type
+ * @param parser for error processing
+ * @return <code>true</code>: instance and children are correct<br>
+ * <code>false</code>: otherwise
+ */
+bool RplASItem::checkAsCalculable(const char* description,
+ RplASClass* expectedClass, RplParser& parser)
+{
+ bool rc = true;
+ if (! check(parser))
+ rc = false;
+ if (rc){
+ RplASCalculable* expr = dynamic_cast<RplASCalculable*>(this);
+ if (expr == NULL)
+ rc = error(LOC_ITEM_AS_INT_1, parser, "%s not calculable: %s",
+ description, nameOfItemType());
+ else if (expr->clazz() != RplASInteger::m_instance)
+ rc = error(LOC_ITEM_AS_INT_2, parser,
+ "%s: wrong type %s instead of integer",
+ description, expr->clazz()->name().constData());
+ }
+ return rc;
+}
+
/**
* @brief Returns the position of the item in the source code.
*
{
m_nextId = 1;
}
+/**
+ * @brief Calculates an integer value.
+ *
+ * @param expr a calculable node
+ * @param thread the execution unit
+ * @return the value described by the node <code>expr</code>
+ */
+int RplASItem::calcAsInteger(RplASItem* expr, RplVMThread& thread)
+{
+ RplASCalculable* expr2 = dynamic_cast<RplASCalculable*>(expr);
+ expr2->calc(thread);
+ RplASVariant& value = thread.popValue();
+ int rc = value.asInt();
+ return rc;
+}
+
+/**
+ * @brief Calculates an boolean value.
+ *
+ * @param expr a calculable node
+ * @param thread the execution unit
+ * @return the value described by the node <code>expr</code>
+ */
+bool RplASItem::calcAsBoolean(RplASItem* expr, RplVMThread& thread)
+{
+ RplASCalculable* expr2 = dynamic_cast<RplASCalculable*>(expr);
+ expr2->calc(thread);
+ RplASVariant& value = thread.popValue();
+ bool rc = value.asBool();
+ return rc;
+}
/**
* @brief Checks the correctness of a statement list.
*
while(list != NULL){
if (! list->check(parser))
- rc = false;
+ rc = false;
+ if (dynamic_cast<RplASStatement*>(list) == NULL)
+ rc = list->error(LOC_ITEM_STATEM_LIST_1, parser, "not a statement: %s",
+ list->nameOfItemType());
RplASNode1* node = dynamic_cast<RplASNode1*>(list);
if (node == NULL){
list->error(LOC_ITEM_STATEM_LIST_1, parser, "not a node: %s",
list->nameOfItemType());
list = NULL;
- } else
+ } else {
list = node->child();
+ }
}
return rc;
}
/**
* @brief Constructor.
*
- * @param dataType the data type (class)
- * @param name the name of the variable
+ * @param clazz the data type (class)
* @param space the current symbol space
+ * @param name the name of the variable
* @param attributes the attributes of the variable
*/
RplASNamedValue::RplASNamedValue(RplASClass* clazz,RplSymbolSpace* space,
if (rc && converter != NULL)
m_child = converter;
if (rc){
- //@ToDo: dynamic subclass of list
+ //@ToDo: dynamic subclass of list / map
m_class = RplASString::m_instance;
rc = m_class != NULL && m_class == RplASInteger::m_instance;
}
RplASCalculable* expr = dynamic_cast<RplASCalculable*> (m_child2);
expr->calc(thread);
RplASVariant& value = thread.popValue();
+ if (thread.tracing())
+ thread.vm()->traceWriter()->format("expr: %s",
+ value.toString().constData());
value.destroyValue();
return 0;
}
return rc;
}
-/** @class RplASCondition rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements a condition.
- *
- * The condition is a statement and a RplASExpr and will be used in other
- * statements like for and while.
- *
- */
-/**
- * @brief Constructor.
- */
-RplASCondition::RplASCondition() :
- RplASNode1(AST_CONDITION),
- RplASCalculable()
-{
-}
-
-/**
- * @brief Calculates the value of the condition
- *
- * @param thread IN/OUT: the bool value of the condition
- */
-void RplASCondition::calc(RplVMThread& thread)
-{
- RplASCalculable* expr = dynamic_cast<RplASCalculable*>(m_child);
- expr->calc(thread);
- if (thread.tracing())
- thread.vm()->traceWriter()->format("condition: %s",
- thread.topOfValues().toString().constData());
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser for error processing
- * @return <code>true</code>: node is correct<br>
- * <code>false</code>: otherwise
- */
-bool RplASCondition::check(RplParser& parser)
-{
- RplASCalculable* expr = dynamic_cast<RplASCalculable*>(m_child);
- if (expr == NULL)
- throw RplASException(m_position, "child of condition is not calculable");
- return false;
-}
-/**
- * @brief Calculates the boolean value and returns it.
- */
-bool RplASCondition::calcAsBool(RplVMThread& thread)
-{
- bool rc = false;
- calc(thread);
- RplASVariant& value = thread.topOfValues();
- switch(value.m_variantType){
- case RplASVariant::VT_FLOAT:
- rc = value.m_value.m_float == 0;
- break;
- case RplASVariant::VT_BOOL:
- rc = value.m_value.m_bool;
- break;
- case RplASVariant::VT_OBJECT:
- rc = value.m_class->boolValueOf(value.m_value.m_object);
- break;
- default:
- rc = false;
- break;
- }
- return rc;
-}
-
-/**
- * @brief Writes the internals into a file.
- *
- * @param writer writes to output
- * @param indent nesting level
- */
-void RplASCondition::dump(RplWriter& writer, int indent)
-{
- char buffer[256];
- writer.formatIndented(indent, "Condition %d Child: %d %s", m_id,
- m_child == NULL ? 0 : m_child->id(),
- positionStr(buffer, sizeof buffer));
- if (m_child != NULL)
- m_child->dump(writer, indent);
-}
/** @class RplASIf rplastree.hpp "rplexpr/rplastree.hpp"
*
*/
bool RplASIf::check(RplParser& parser)
{
- bool rc = m_child2 != NULL && m_child2->check(parser)
- && (m_child3 == NULL || checkStatementList(m_child3, parser))
- && (m_child4 == NULL || checkStatementList(m_child4, parser));
+ bool rc = true;
+ if (m_child2 == NULL)
+ rc = ensureError(parser, "'if' misses condition");
+ else if (m_child2->checkAsCalculable("condition", RplASBoolean::m_instance,
+ parser))
+ rc = false;
+ if (m_child3 != NULL && ! checkStatementList(m_child3, parser))
+ rc = false;
+ if (m_child4 != NULL && ! checkStatementList(m_child4, parser))
+ rc = false;
return rc;
}
int RplASIf::execute(RplVMThread& thread)
{
int rc = 0;
- RplASCondition* condition = dynamic_cast<RplASCondition*>(m_child2);
- if (condition == NULL)
- throw RplASException(m_child2 == NULL ? m_position : m_child2->position(),
- "if statement: not a condition");
- RplASStatement* body = NULL;
- RplASItem* list;
- if(condition->calcAsBool(thread)){
- list = m_child3;
- body = dynamic_cast<RplASStatement*>(m_child3);
- if (body == NULL)
- throw RplASException(m_child2 == NULL ? m_position : m_child2->position(),
- "if statement: then-part is not a statement");
- } else if (m_child4 != NULL){
- list = m_child4;
- body = dynamic_cast<RplASStatement*>(m_child4);
- if (body == NULL)
- throw RplASException(m_child4->position(),
- "if statement: else-part is not a statement");
- }
- if ( (rc = executeStatementList(list, thread)) != 0){
- if (rc < 0)
- rc--;
- else if (rc > 0)
- rc++;
+ bool condition = calcAsBoolean(m_child2, thread);
+ if (thread.tracing())
+ thread.vm()->traceWriter()->format("if %s", condition ? "true" : "false");
+
+ RplASItem* list = condition ? m_child3 : m_child4;
+ if (list != NULL){
+ if ( (rc = executeStatementList(list, thread)) != 0){
+ if (rc < 0)
+ rc--;
+ else if (rc > 0)
+ rc++;
+ }
}
return rc;
}
*/
bool RplASForCounted::check(RplParser& parser)
{
- return false;
+ bool rc = true;
+ RplASNamedValue* var = NULL;
+ if (m_child3 != NULL){
+ var = dynamic_cast<RplASNamedValue*>(m_child3);
+ if (! m_child3->check(parser))
+ rc = false;
+ if (var == NULL)
+ rc = error(LOC_FORC_CHECK_1, parser, "not a variable: %s",
+ m_child3->nameOfItemType());
+ }
+ RplASCalculable* expr;
+ if (m_child4 != NULL && ! m_child4->checkAsCalculable("start value",
+ RplASInteger::m_instance, parser))
+ rc = false;
+ if (m_child5 != NULL && ! m_child5->checkAsCalculable("end value",
+ RplASInteger::m_instance, parser))
+ rc = false;
+ if (m_child6 != NULL && ! m_child6->checkAsCalculable("step value",
+ RplASInteger::m_instance, parser))
+ rc = false;
+ if (m_child2 != NULL && ! checkStatementList(m_child2, parser))
+ rc = false;
+ return rc;
}
/**
if (body == NULL)
throw RplASException(m_child2 == NULL ? m_position : m_child2->position(),
"forc statement: body is not a statement");
- int start = 1;
- int step = 1;
- int end = 0;
- RplASNamedValue* var = NULL;
- if (m_child3 != NULL){
- var = dynamic_cast<RplASNamedValue*>(m_child3);
- }
+ int start = m_child4 == NULL ? 1 : calcAsInteger(m_child4, thread);
+ int end = m_child5 == NULL ? 0 : calcAsInteger(m_child5, thread);
+ int step = m_child6 == NULL ? 1 : calcAsInteger(m_child6, thread);
+ RplASNamedValue* var = m_child3 == NULL
+ ? NULL : dynamic_cast<RplASNamedValue*>(m_child3);
+ if (thread.tracing())
+ thread.vm()->traceWriter()->format("for %s from %d to %d step %d",
+ var == NULL ? "?" : var->name().constData(),
+ start, end, step);
+
for(int ii = start; ii <= end; ii += step){
- body->execute(thread);
+ //@ToDo: assign to the variable
+ int rc2 = body->execute(thread);
+ if (rc2 != 0){
+ if (rc2 > 0){
+ // rc comes from "break";
+ rc = rc2 - 1;
+ } else {
+ // rc comes from "continue";
+ if (rc2 == -1)
+ continue;
+ else
+ rc = rc2 + 1;
+ }
+ break;
+ }
}
return rc;
}
*/
bool RplASWhile::check(RplParser& parser)
{
- return false;
+ bool rc = true;
+ if (m_child2 == NULL)
+ ensureError(parser, "missing condition for 'while''");
+ else
+ rc = m_child2->checkAsCalculable("condition", RplASBoolean::m_instance,
+ parser);
+ if (m_child3 != NULL && ! checkStatementList(m_child3, parser))
+ rc = false;
+ return rc;
}
/**
{
int rc = 0;
RplASStatement* body = dynamic_cast<RplASStatement*>(m_child3);
- if (body == NULL)
- throw RplASException(m_child3 == NULL ? m_position : m_child3->position(),
- "while statement: body is not a statement");
- RplASCondition* condition = dynamic_cast<RplASCondition*>(m_child2);
- if (condition == NULL)
- throw RplASException(m_child2 == NULL ? m_position : m_child2->position(),
- "for statement: not a condition");
- while(condition->calcAsBool(thread)){
- body->execute(thread);
+ if (thread.tracing())
+ thread.vm()->traceWriter()->write("while");
+ while(calcAsBoolean(m_child2, thread)){
+ int rc2 = body->execute(thread);
+ if (rc2 != 0){
+ if (rc2 > 0){
+ // rc comes from "break";
+ rc = rc2 - 1;
+ } else {
+ // rc comes from "continue";
+ if (rc2 == -1)
+ continue;
+ else
+ rc = rc2 + 1;
+ }
+ break;
+ }
}
return rc;
}
*/
bool RplASRepeat::check(RplParser& parser)
{
- return false;
+ bool rc = true;
+ if (m_child3 != NULL && ! checkStatementList(m_child3, parser))
+ rc = false;
+ if (m_child2 == NULL)
+ ensureError(parser, "missing condition for 'repeat''");
+ else if (! m_child2->checkAsCalculable("condition", RplASBoolean::m_instance,
+ parser))
+ rc = false;
+ return rc;
}
/**
{
int rc = 0;
RplASStatement* body = dynamic_cast<RplASStatement*>(m_child3);
- if (body == NULL)
- throw RplASException(m_child3 == NULL ? m_position : m_child3->position(),
- "repeat statement: body is not a statement");
- RplASCondition* condition = dynamic_cast<RplASCondition*>(m_child2);
- if (condition == NULL)
- throw RplASException(m_child2 == NULL ? m_position : m_child2->position(),
- "repeat statement: not a condition");
+ if (thread.tracing())
+ thread.vm()->traceWriter()->write("repeat");
do {
- body->execute(thread);
- } while(condition->calcAsBool(thread));
+ int rc2 = body->execute(thread);
+ if (rc2 != 0){
+ if (rc2 > 0){
+ // rc comes from "break";
+ rc = rc2 - 1;
+ } else {
+ // rc comes from "continue";
+ if (rc2 == -1)
+ continue;
+ else
+ rc = rc2 + 1;
+ }
+ break;
+ }
+ } while(! calcAsBoolean(m_child2, thread));
return rc;
}
*/
bool RplASMethodCall::check(RplParser& parser)
{
- return false;
+ bool rc = true;
+ RplASExprStatement* args = dynamic_cast<RplASExprStatement*>(m_child2);
+ int argCount = 0;
+ RplASMethod* method = m_method;
+ RplASExprStatement* params = dynamic_cast<RplASExprStatement*>(method->child2());
+ while (args != NULL && params != NULL){
+ argCount++;
+ RplASCalculable* argExpr = dynamic_cast<RplASCalculable*>(args->child2());
+ if (argExpr == NULL)
+ rc = error(LOC_METHOD_CALL_CHECK_1, parser,
+ "argument %d misses expr", argCount);
+ else {
+
+ }
+ }
+
+ return rc;
}
*/
int RplASMethodCall::execute(RplVMThread& thread)
{
- return 0;
+ int rc = 0;
+
+ return rc;
}
RplASMethod* RplASMethodCall::method() const
*
* @return the first element of an argument list
*/
-RplASArgument* RplASMethodCall::arg1() const
+RplASExprStatement* RplASMethodCall::arg1() const
{
- return dynamic_cast<RplASArgument*>(m_child2);
+ return dynamic_cast<RplASExprStatement*>(m_child2);
}
/** @class RplASException rplastree.hpp "rplexpr/rplastree.hpp"
m_sibling = sibling;
}
-/** @class RplASArgument rplastree.hpp "rplexpr/rplastree.hpp"
- *
- * @brief Implements an argument of a method for the Abstract Syntax Tree.
- *
- * <code>m_child</code>: next argument<br>
- * <code>m_child2</code>: expression
- */
-/**
- * @brief constructor
- */
-RplASArgument::RplASArgument() :
- RplASNode2(AST_ARGUMENT)
-{
-}
-
-/**
- * @brief Checks the correctness of the instance.
- *
- * @param parser for error processing
- * @return <code>true</code>: node is correct<br>
- * <code>false</code>: otherwise
- */
-bool RplASArgument::check(RplParser& parser)
-{
- return false;
-}
-
-/**
- * @brief Writes the internals of the instance into a file.
- *
- * @param writer writes to output
- * @param no current number of the argument: 1..N
- * @param indent nesting level
- */
-void RplASArgument::dumpOne(RplWriter& writer, int no, int indent)
-{
- int succ = m_child == NULL ? 0 : m_child->id();
- writer.formatIndented(indent, "arg %d id: %d expr: %d succ: %d", no, m_id,
- child2()->id(), succ);
- m_child2->dump(writer, indent + 1);
-}
-
-/**
- * @brief Writes the internals of the instance into a file.
- *
- * @param writer writes to output
- * @param indent nesting level
- */
-void RplASArgument::dump(RplWriter& writer, int indent)
-{
-
- RplASArgument* current = this;
- int no = 0;
- do {
- current->dumpOne(writer, ++no, indent);
- current = static_cast<RplASArgument*>(current->child());
- } while (current != NULL);
-}
/** @class RplASField rplastree.hpp "rplexpr/rplastree.hpp"
*
* @pre first token of the definition is read
* @post token behind the definition is read: ';', ',', ')'
* @param attribute attribute of the variable: A_PARAM...
+ * @return a variable/parameter definition
*/
-RplASItem* RplMFParser::parseVarDefinition(RplASNamedValue::Attributes attribute)
+RplASVarDefinition* RplMFParser::parseVarDefinition(
+ RplASNamedValue::Attributes attribute)
{
int attributes = attribute;
RplToken* token = m_lexer.currentToken();
token = m_lexer.nextNonSpaceToken();
if (! token->isOperator(O_RPARENTH)){
m_lexer.undoLastToken();
- RplASArgument* args = parseArguments();
+ RplASExprStatement* args = parseArguments();
call->setChild2(args);
readNext = false;
}
return statement;
}
+/**
+ * @brief Parses a local variable.
+ *
+ * @return the variable definition
+ */
RplASItem* RplMFParser::parseLocalVar(){
RplASItem* rc = parseVarDefinition(RplASNamedValue::A_NONE);
return rc;
* @post token behind ')' is read
* @return
*/
-RplASExprStatement* RplMFParser::parseParameterList(){
- RplASExprStatement* rc = NULL;
- RplASExprStatement* last = NULL;
+RplASVarDefinition* RplMFParser::parseParameterList(){
+ RplASVarDefinition* rc = NULL;
+ RplASVarDefinition* last = NULL;
const RplSourcePosition* startPos = m_lexer.currentPosition();
RplASItem* definition = NULL;
do {
if (definition != NULL)
m_lexer.nextNonSpaceToken();
- definition = parseVarDefinition(RplASNamedValue::A_PARAM);
- RplASExprStatement *current = new RplASExprStatement();
- current->setChild2(definition);
+ RplASVarDefinition* current = parseVarDefinition(RplASNamedValue::A_PARAM);
if (rc == NULL){
rc = current;
} else {
if (! token->isOperator(O_LPARENTH, O_COLON))
syntaxError(L_PARSE_METH_NO_LPARENTH, "'(' or ':' expected");
- RplASExprStatement* parameterList = NULL;
+ RplASVarDefinition* parameterList = NULL;
method = new RplASMethod(name, m_tree);
method->setPosition(startPos);
RplSymbolSpace* symbols = m_tree.currentSpace();
* @post the token behind the ')' is read
* @return the first element of the argument list
*/
-RplASArgument* RplMFParser::parseArguments()
+RplASExprStatement* RplMFParser::parseArguments()
{
- RplASArgument* first = NULL;
- RplASArgument* last = NULL;
+ RplASExprStatement* first = NULL;
+ RplASExprStatement* last = NULL;
bool again = false;
do {
RplASItem* expr = parseExpr(0);
if (! m_lexer.currentToken()->isOperator(O_COMMA, O_RPARENTH))
syntaxError(L_PARSE_ARGS_NO_COMMA_OR_PARENT, "',' or ')' expected");
again = m_lexer.currentToken()->isOperator(O_COMMA);
- RplASArgument* current = new RplASArgument();
+ RplASExprStatement* current = new RplASExprStatement();
current->setPosition(expr->position());
current->setChild2(expr);
if (first == NULL)
rc endf
= <test> (module) parent: $global
== Methods:
-Method <NoneType> fac() id: 1 parent: <test> args: 4 body: 6 <test>:0:55
- Expr id: 4 expr: 3 succ: 0
- varDef Int n id: 3 namedValue: 2 value: 0 succ: 0 <test>:1:23
- namedValue n id: 2 attr: 0x22 <test>:1:23
- varDef Int rc id: 6 namedValue: 5 value: 0 succ: 7 <test>:2:4
- namedValue rc id: 5 attr: 0x0 <test>:2:4
- If id: 7 condition: 9 then: 14 else: 24 succ: 26<test>:2:8
- BinOp id: 9 op: <= (34) left: 8 right: 10 <test>:2:14
- namedValue rc id: 8 attr: 0x0 <test>:2:14
- const id: 10 value: 1 <test>:2:17
- Expr id: 14 expr: 12 succ: 0 <test>:2:27
- BinOp id: 12 op: = (1) left: 11 right: 13 <test>:2:27
- namedValue rc id: 11 attr: 0x0 <test>:2:27
- const id: 13 value: 1 <test>:2:29
- Expr id: 24 expr: 16 succ: 0 <test>:2:39
- BinOp id: 16 op: = (1) left: 15 right: 18 <test>:2:39
- namedValue rc id: 15 attr: 0x0 <test>:2:39
- BinOp id: 18 op: * (19) left: 17 right: 19 <test>:2:42
- namedValue n id: 17 attr: 0x0 <test>:2:42
- call fac Id: 19 args: 23 parent: 0 succ: 0 <test>:2:46
- arg 1 id: 23 expr: 21 succ: 0
- BinOp id: 21 op: - (18) left: 20 right: 22 <test>:2:48
- namedValue n id: 20 attr: 0x0 <test>:2:48
- const id: 22 value: 1 <test>:2:49
- Expr id: 26 expr: 25 succ: 0 <test>:3:3
- namedValue rc id: 25 attr: 0x0 <test>:3:3
+Method <NoneType> fac() id: 1 parent: <test> args: 3 body: 5 <test>:0:55
+ varDef Int n id: 3 namedValue: 2 value: 0 succ: 0 <test>:1:23
+ namedValue n id: 2 attr: 0x22 <test>:1:23
+ varDef Int rc id: 5 namedValue: 4 value: 0 succ: 6 <test>:2:4
+ namedValue rc id: 4 attr: 0x0 <test>:2:4
+ If id: 6 condition: 8 then: 13 else: 23 succ: 25<test>:2:8
+ BinOp id: 8 op: <= (34) left: 7 right: 9 <test>:2:14
+ namedValue rc id: 7 attr: 0x0 <test>:2:14
+ const id: 9 value: 1 <test>:2:17
+ Expr id: 13 expr: 11 succ: 0 <test>:2:27
+ BinOp id: 11 op: = (1) left: 10 right: 12 <test>:2:27
+ namedValue rc id: 10 attr: 0x0 <test>:2:27
+ const id: 12 value: 1 <test>:2:29
+ Expr id: 23 expr: 15 succ: 0 <test>:2:39
+ BinOp id: 15 op: = (1) left: 14 right: 17 <test>:2:39
+ namedValue rc id: 14 attr: 0x0 <test>:2:39
+ BinOp id: 17 op: * (19) left: 16 right: 18 <test>:2:42
+ namedValue n id: 16 attr: 0x0 <test>:2:42
+ call fac Id: 18 args: 22 parent: 0 succ: 0 <test>:2:46
+ Expr id: 22 expr: 20 succ: 0 <test>:2:48
+ BinOp id: 20 op: - (18) left: 19 right: 21 <test>:2:48
+ namedValue n id: 19 attr: 0x0 <test>:2:48
+ const id: 21 value: 1 <test>:2:49
+ Expr id: 25 expr: 24 succ: 0 <test>:3:3
+ namedValue rc id: 24 attr: 0x0 <test>:3:3
= <test>.fac (method) parent: <test>
== Variables:
varDef Int n id: 3 namedValue: 2 value: 0 succ: 0 <test>:1:23
namedValue n id: 2 attr: 0x22 <test>:1:23
- varDef Int rc id: 6 namedValue: 5 value: 0 succ: 7 <test>:2:4
- namedValue rc id: 5 attr: 0x0 <test>:2:4
+ varDef Int rc id: 5 namedValue: 4 value: 0 succ: 6 <test>:2:4
+ namedValue rc id: 4 attr: 0x0 <test>:2:4