// Parse void MultiNode::Parse(Parser &parser, Parser::size_type start, Parser::size_type end, Parser::size_type v1) { Parser::size_type pos, last; int plevel = 0; // Sanity check if(start >= end) throw(SyntaxException()); // Look last = start; for(pos = start; pos <= end; pos++) { switch(parser[pos].GetType()) { case Token::TypeOpenParenthesis: { plevel++; break; }; case Token::TypeCloseParenthesis: { plevel--; if(plevel < 0) { UnmatchedParenthesisException e; e.SetStart(parser[pos].GetStart()); e.SetEnd(parser[pos].GetEnd()); throw(e); } break; } case Token::TypeSemicolon: { if(plevel == 0) { if(pos > last) { // Everything from last to pos - 1 aptr(Node) n(parser.ParseRegion(last, pos - 1)); m_nodes.push_back(n.get()); n.release(); } else { SyntaxException e; e.SetStart(parser[last].GetStart()); e.SetEnd(parser[pos].GetEnd()); throw(e); } last = pos + 1; } break; } default: break; } } // plevel should be zero if(plevel != 0) { UnmatchedParenthesisException e; e.SetStart(parser[pos].GetStart()); e.SetEnd(parser[pos].GetEnd()); throw(e); } // If the end was not a semicolon, test it as well if(last < end + 1) { aptr(Node) n(parser.ParseRegion(last, end)); m_nodes.push_back(n.get()); n.release(); } }
// Parse expression void FunctionNode::Parse(Parser &parser, Parser::size_type start, Parser::size_type end, Parser::size_type v1) { Parser::size_type pos, last; int plevel = 0; // Sanity check (start/end are function parenthesis) if(start >= end) throw(SyntaxException()); // Look last = start + 1; for(pos = start + 1; pos <= end && start + 1 != end; pos++) { switch(parser[pos].GetType()) { case Token::TypeOpenParenthesis: { plevel++; break; }; case Token::TypeComma: case Token::TypeCloseParenthesis: { // Handle Close parenthesis for all but the last one at the end if(parser[pos].GetType() == Token::TypeCloseParenthesis && pos != end) { plevel--; if(plevel < 0) { UnmatchedParenthesisException e; e.SetStart(parser[pos].GetStart()); e.SetEnd(parser[pos].GetEnd()); throw(e); } break; } // Handle comma, or if it was the ending parenthesis treat it like comma if(plevel == 0) { if(pos > last) { // reference parameter? if(parser[last].GetType() == Token::TypeAmpersand) { // Reference parameter, check position and type of next parameter if(last == pos - 2 && parser[last + 1].GetType() == Token::TypeIdentifier) { // Get value list ValueList *vlist = m_expr->GetValueList(); if(vlist == 0) { NoValueListException e; e.SetStart(parser[last + 1].GetStart()); e.SetEnd(parser[last + 1].GetEnd()); throw(e); } // Get name string ident = parser[last + 1].GetIdentifier(); // Make sure it is not a constant if(vlist->IsConstant(ident)) { ConstantReferenceException e(ident); e.SetStart(parser[last + 1].GetStart()); e.SetEnd(parser[last + 1].GetEnd()); throw(e); } // Get address double *vaddr = vlist->GetAddress(ident); if(vaddr == 0) { // Try to add it and get again vlist->Add(ident); vaddr = vlist->GetAddress(ident); } if(vaddr == 0) { NotFoundException e(ident); e.SetStart(parser[last + 1].GetStart()); e.SetEnd(parser[last + 1].GetEnd()); throw(e); } // Add it m_refs.push_back(vaddr); } else { SyntaxException e; e.SetStart(parser[last].GetStart()); e.SetEnd(parser[pos].GetEnd()); throw(e); } } // TypeAmpersand else { // Create node aptr(Node) n(parser.ParseRegion(last, pos - 1)); m_nodes.push_back(n.get()); n.release(); } } else { SyntaxException e; e.SetStart(parser[pos].GetStart()); e.SetEnd(parser[pos].GetEnd()); throw(e); } last = pos + 1; } break; } default: break; } } // plevel should be zero if(plevel != 0) { UnmatchedParenthesisException e; e.SetStart(parser[end].GetStart()); e.SetEnd(parser[end].GetEnd()); throw(e); } // Check argument count if(m_argMin != -1 && m_nodes.size() < (vector<Node*>::size_type)m_argMin) { InvalidArgumentCountException e(GetName()); e.SetStart(parser[start].GetStart()); e.SetEnd(parser[end].GetEnd()); throw(e); } if(m_argMax != -1 && m_nodes.size() > (vector<Node*>::size_type)m_argMax) { InvalidArgumentCountException e(GetName()); e.SetStart(parser[start].GetStart()); e.SetEnd(parser[end].GetEnd()); throw(e); } if(m_refMin != -1 && m_refs.size() < (vector<double*>::size_type)m_refMin) { InvalidArgumentCountException e(GetName()); e.SetStart(parser[start].GetStart()); e.SetEnd(parser[end].GetEnd()); throw(e); } if(m_refMax != -1 && m_refs.size() > (vector<double*>::size_type)m_refMax) { InvalidArgumentCountException e(GetName()); e.SetStart(parser[start].GetStart()); e.SetEnd(parser[end].GetEnd()); throw(e); } }
// Parse a region of tokens Node *Parser::ParseRegion(Parser::size_type start, Parser::size_type end) { size_type pos; size_type fgopen = (size_type)-1; size_type fgclose = (size_type)-1; size_type assignindex = (size_type)-1; size_type addsubindex = (size_type)-1; size_type muldivindex = (size_type)-1; size_type posnegindex = (size_type)-1; size_type expindex = (size_type)-1; bool multiexpr = false; int plevel = 0; // Check simple syntax if(start > end) throw(SyntaxException()); // Scan through tokens for(pos = start; pos <= end; pos++) { switch(m_tokens[pos].GetType()) { case Token::TypeOpenParenthesis: { plevel++; // Opening of first group? if(plevel == 1 && fgopen == (size_type)-1) fgopen = pos; break; }; case Token::TypeCloseParenthesis: { plevel--; // First group closed? if(plevel == 0 && fgclose == (size_type)-1) fgclose = pos; if(plevel < 0) { UnmatchedParenthesisException e; e.SetStart(m_tokens[pos].GetStart()); e.SetEnd(m_tokens[pos].GetEnd()); throw(e); } break; } case Token::TypeEqual: { if(plevel == 0) { if(assignindex == (size_type)-1) assignindex = pos; } break; } case Token::TypeAsterisk: case Token::TypeForwardSlash: { if(plevel == 0) { muldivindex = pos; } break; } case Token::TypeHat: { if(plevel == 0) { expindex = pos; } break; } case Token::TypePlus: case Token::TypeHyphen: { if(plevel == 0) { if(pos == start) { // Positive or negative sign if(posnegindex == (size_type)-1) posnegindex = pos; } else { // What is before us switch(m_tokens[pos - 1].GetType()) { case Token::TypeEqual: case Token::TypePlus: case Token::TypeHyphen: case Token::TypeAsterisk: case Token::TypeForwardSlash: case Token::TypeHat: // After any of these, we are a positive/negative if(posnegindex == (size_type)-1) posnegindex = pos; break; default: // After any other, we are addition/subtration addsubindex = pos; break; } } } break; } case Token::TypeSemicolon: { if(plevel == 0) { multiexpr = true; } break; } } } // plevel should be 0 if(plevel != 0) { UnmatchedParenthesisException e; e.SetStart(end); e.SetEnd(end); throw(e); } // Parse in certain order to maintain order of operators // Multi-expression first if(multiexpr) { auto_ptr<Node> n(new MultiNode(m_expr)); n->Parse(*this, start, end); return n.release(); } else if(assignindex != (size_type)-1) { // Assignment next auto_ptr<Node> n(new AssignNode(m_expr)); n->Parse(*this, start, end, assignindex); return n.release(); } else if(addsubindex != (size_type)-1) { // Addition/subtraction next if(m_tokens[addsubindex].GetType() == Token::TypePlus) { // Addition auto_ptr<Node> n(new AddNode(m_expr)); n->Parse(*this, start, end, addsubindex); return n.release(); } else { // Subtraction auto_ptr<Node> n(new SubtractNode(m_expr)); n->Parse(*this, start, end, addsubindex); return n.release(); } } else if(muldivindex != (size_type)-1) { // Multiplication/division next if(m_tokens[muldivindex].GetType() == Token::TypeAsterisk) { // Multiplication auto_ptr<Node> n(new MultiplyNode(m_expr)); n->Parse(*this, start, end, muldivindex); return n.release(); } else { // Division auto_ptr<Node> n(new DivideNode(m_expr)); n->Parse(*this, start, end, muldivindex); return n.release(); } } else if(posnegindex == start) { // Positive/negative next, must be at start and check before exponent if(m_tokens[posnegindex].GetType() == Token::TypePlus) { // Positive return ParseRegion(posnegindex + 1, end); } else { auto_ptr<Node> n(new NegateNode(m_expr)); n->Parse(*this, start, end, posnegindex); return n.release(); } } else if(expindex != (size_type)-1) { // Exponent auto_ptr<Node> n(new ExponentNode(m_expr)); n->Parse(*this, start, end, expindex); return n.release(); } else if(posnegindex != (size_type)-1) { // Check pos/neg again. After testing for exponent, a pos/neg // at plevel 0 is syntax error SyntaxException e; e.SetStart(m_tokens[posnegindex].GetStart()); e.SetEnd(m_tokens[posnegindex].GetEnd()); throw(e); } else if(fgopen == start) { // Group parenthesis, make sure something in between them if(fgclose == end && fgclose > fgopen + 1) { return ParseRegion(fgopen + 1, fgclose - 1); } else { SyntaxException e; e.SetStart(m_tokens[fgopen].GetStart()); if(fgclose == (size_type)-1) e.SetEnd(m_tokens[fgopen].GetEnd()); else e.SetEnd(m_tokens[fgclose].GetEnd()); throw(e); } } else if(fgopen == start + 1) { // Function if(fgclose == end) { // Find function list FunctionList *flist = m_expr->GetFunctionList(); if(flist == 0) { NoFunctionListException e; e.SetStart(m_tokens[start].GetStart()); e.SetEnd(m_tokens[start].GetEnd()); throw(e); } // Get name string ident = m_tokens[start].GetIdentifier(); // Create function node auto_ptr<FunctionNode> n(flist->Create(ident, m_expr)); if(n.get()) { n->Parse(*this, fgopen, fgclose); } else { NotFoundException e(ident); e.SetStart(m_tokens[start].GetStart()); e.SetEnd(m_tokens[start].GetEnd()); throw(e); } return n.release(); } else { SyntaxException e; e.SetStart(m_tokens[fgopen].GetStart()); if(fgclose == (size_type)-1) e.SetEnd(m_tokens[fgopen].GetEnd()); else e.SetEnd(m_tokens[fgclose].GetEnd()); throw(e); } } else if(start == end) { // Value, variable, or constant if(m_tokens[start].GetType() == Token::TypeIdentifier) { // Variable/constant auto_ptr<Node> n(new VariableNode(m_expr)); n->Parse(*this, start, end); return n.release(); } else { // Value auto_ptr<Node> n(new ValueNode(m_expr)); n->Parse(*this, start, end); return n.release(); } } else { // Unknown, syntax SyntaxException e; e.SetStart(m_tokens[pos].GetStart()); e.SetEnd(m_tokens[pos].GetEnd()); throw(e); } }