📄 expr.cxx
字号:
}//}}}//}}}//{{{ next_token() // ----------------------------------------------------------------------------// Work out what the next token is. This includes the handling of// strings, integers, doubles, and references.static voidnext_token() throw(CdlParseException, std::bad_alloc){ CYG_REPORT_FUNCNAMETYPE("next_token", "token %d"); // Make sure there is no dross left lying around from the previous call. current_token = T_Invalid; current_string = ""; current_reference = ""; current_int = 0; current_double = 0.0; current_format = CdlValueFormat_Default; // Skip leading white space. This includes newlines, tabs, etc, // consider the case of: // ... // legal_values { // 1 // 2 // 4 // .. // } // ... // which is perfectly legitimate. White space inside strings // is handled by the string literal code, and does not get filtered // out here. // // Exactly which characters are white-space is implementation-defined, // so a special check for EOF is in order. while ((EOF != current_char) && isspace(current_char)) { next_char(); } // Remember the token starting point. next_char() has actually moved // the index on by one. token_start = current_index - 1; // The simple cases can be handled inline, the more complicated cases // involve other functions switch(current_char) { case EOF: current_token = T_EOD; break; case '"': process_string(); break; case '(': current_token = T_OpenBracket; next_char(); break; case ')': current_token = T_CloseBracket; next_char(); break; // At this level it is not possible to distinguish between // unary and binary operators, so no attempt is made to // turn - and + into part of a number. case '-': current_token = T_Minus; next_char(); break; case '+': current_token = T_Plus; next_char(); break; case '*': current_token = T_Times; next_char(); break; case '/': current_token = T_Divide; next_char(); break; case '!': next_char(); if ('=' == current_char) { current_token = T_NotEqual; next_char(); } else { current_token = T_Exclamation; } break; case '~': current_token = T_Tilde; next_char(); break; case '?': current_token = T_Questionmark; next_char(); break; case '%': current_token = T_Remainder; next_char(); break; case '<': next_char(); if ('<' == current_char) { current_token = T_LeftShift; next_char(); } else if ('=' == current_char) { current_token = T_LessEqual; next_char(); } else { current_token = T_LessThan; } break; case '>': next_char(); if ('>' == current_char) { current_token = T_RightShift; next_char(); } else if ('=' == current_char) { current_token = T_GreaterEqual; next_char(); } else { current_token = T_GreaterThan; } break; case '=': next_char(); if ('=' != current_char) { throw CdlParseException(std::string("Incomplete == operator in expression.\n") + get_error_location()); } else { current_token = T_Equal; next_char(); } break; case '&': next_char(); if ('&' == current_char) { current_token = T_And; next_char(); } else { current_token = T_BitAnd; } break; case '^': current_token = T_BitXor; next_char(); break; case '|': next_char(); if ('|' == current_char) { current_token = T_Or; next_char(); } else { current_token = T_BitOr; } break; case ':': current_token = T_Colon; next_char(); break; default: // String constants have been handled already. The only // valid tokens that are left are numbers, references and // the rang eoperator. // // Numbers should begin with a digit (plus and minus are // tokenized separately). // // References must be valid C preprocessor symbols, i.e. // they must begin with either a letter or an underscore. // The range operator is handled most conveniently as // a special case of a reference. if (isdigit(current_char)) { process_number(); } else if (('_' == current_char) || (('a' <= current_char) && (current_char <= 'z')) || (('A' <= current_char) && (current_char <= 'Z'))) { process_reference(); if ("to" == current_reference) { current_reference = ""; current_token = T_Range; } else { current_token = T_Reference; } } else { std::string msg = "Unexpected character '"; msg += (char) current_char; msg += "' in expression.\n"; msg += get_error_location(); throw CdlParseException(msg); } break; } CYG_REPORT_RETVAL(current_token);}//}}}//{{{ initialise_tokenisation() // ----------------------------------------------------------------------------// This is called at the start of expression parsing. It// sets up the appropriate statics, and provides initial// values for current_char and current_token.static voidinitialise_tokenisation(std::string data, int index){ CYG_REPORT_FUNCNAME("initialise_tokenization"); current_data = data; current_index = static_cast<unsigned int>(index); token_start = current_index; next_char(); next_token(); CYG_REPORT_RETURN();}//}}}//}}}//{{{ Syntactic analysis // ----------------------------------------------------------------------------// Syntactic analysis.//// The BNF of CDL expressions is something like this://// <expression> ::= <conditional>// <conditional> ::= <or> ? <conditional> : <conditional> | <or>// <or> ::= <and> [<or op> <and>] ||// <and> ::= <bitor> [<and op> <bitor>] ??// <bitor> ::= <bitxor> [<bitor op> <bitxor>] |// <bitxor> ::= <bitand> [<bitxor op> <bitand>] ^// <bitand> ::= <eq> [<bitand op> <eq>] &// <eq> ::= <comp> [<eq op> <comp>] == !=// <comp> ::= <shift> [<comp op> <shift>] < <= > >=// <shift> ::= <add> [<shift op> <add>] << >>// <add> ::= <mult> [<add op> <mult>] + -// <mult> ::= <unary> [<mult op> <unary>] * / %// <unary> ::= -<unary> | +<unary> | !<unary> | *<unary> | ?<unary> |// <string constant> | <integer constant> |// <double constant> | <reference> |// ( <expression> )//// There are separate functions for each of these terms.// A forward declaration, needed for bracketed subexpressions.static void parse_expression(CdlExpression) throw(CdlParseException, std::bad_alloc);// A utility to add a reference to the current expression, returning// the index.static intpush_reference(CdlExpression expr, const std::string& reference){ CYG_REPORT_FUNCNAMETYPE("push_reference", "new index %d"); CYG_PRECONDITION_CLASSC(expr); CdlReference ref(reference); expr->references.push_back(ref); int result = (int) expr->references.size() - 1; CYG_REPORT_RETVAL(result); return result;}// A utility to add a subexpression, returning its index.static voidpush_subexpression(CdlExpression expr, const CdlSubexpression& subexpr){ CYG_REPORT_FUNCNAME("push_subexpression"); CYG_PRECONDITION_CLASSC(expr); expr->sub_expressions.push_back(subexpr); expr->first_subexpression = ((int) expr->sub_expressions.size()) - 1; CYG_REPORT_RETURN();}// Another utility to hold of the most recent subexpressionstatic CdlSubexpression¤t_subexpression(CdlExpression expr){ CYG_REPORT_FUNCNAME("current_subexpression"); CdlSubexpression& result = expr->sub_expressions[expr->first_subexpression]; CYG_REPORT_RETURN(); return result;}static voidparse_unary(CdlExpression expr) throw(CdlParseException, std::bad_alloc){ CYG_REPORT_FUNCNAME("parse_operand"); CYG_REPORT_FUNCARG1XV(expr); CYG_PRECONDITION_CLASSC(expr); CdlSubexpression subexpr; switch(current_token) { case T_EOD : { // This warrants a special case throw CdlParseException("End of expression reached when expecting an operand.\n" + get_error_location()); } case T_Reference : { subexpr.op = CdlExprOp_Reference; subexpr.reference_index = push_reference(expr, current_reference); push_subexpression(expr, subexpr); next_token(); break; } case T_String : { subexpr.op = CdlExprOp_StringConstant; subexpr.constants = current_string; push_subexpression(expr, subexpr); next_token(); break; } case T_Integer : { subexpr.op = CdlExprOp_IntegerConstant; subexpr.constants.set_integer_value(current_int, current_format); push_subexpression(expr, subexpr); next_token(); break; } case T_Double : { subexpr.op = CdlExprOp_DoubleConstant; subexpr.constants.set_double_value(current_double, current_format); push_subexpression(expr, subexpr); next_token(); break; } case T_OpenBracket : { next_token(); parse_expression(expr); if (T_CloseBracket != current_token) { throw CdlParseException("Missing close bracket after subexpression.\n" + get_error_location()); } next_token(); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -