📄 expr.cxx
字号:
} if (!isdigit(current_char)) { throw CdlParseException("Invalid floating point constant, expected a digit for the exponent.\n" + get_error_location()); } is_float = true; do { tmp += (char) current_char; next_char(); } while(isdigit(current_char)); } if (is_float) { if (!Cdl::string_to_double(tmp, current_double)) { throw CdlParseException("Invalid floating point constant `" + tmp + "'.\n" + get_error_location()); } else { current_token = T_Double; } } else { if (!Cdl::string_to_integer(tmp, current_int)) { throw CdlParseException("Invalid integer constant `" + tmp + "'.\n" + get_error_location()); } else { current_token = T_Integer; } } check_number_termination(); CYG_REPORT_RETURN();}//}}}//{{{ process_alphanumeric() // The start of an alphanumeric sequence has been detected. This may// be a reference, a function call, or an operator like eq or to. All// such sequences must be a valid C preprocessor name, so the only// characters allowed are underscore, upper and lower case characters,// and digits. The first character cannot be a digit, but that has// been checked already.//// Some care has to be taken with locale's, the C library may decide// that a character is a letter even though the same character is not// valid as far as the preprocessor is concerned.static voidprocess_alphanumeric(){ CYG_REPORT_FUNCNAME("process_alphanumeric"); do { current_reference += (char) current_char; next_char(); } while (('_' == current_char) || isdigit(current_char) || (('a' <= current_char) && (current_char <= 'z')) || (('A' <= current_char) && (current_char <= 'Z'))); CYG_REPORT_RETURN();}//}}}//{{{ process_special() // Usually an alphanumeric sequence of characters is a reference, e.g.// CYGPKG_KERNEL. However there are only so many special characters// available so some operators are implemented as a sequence, e.g. // "to". CDL also supports functions like is_substr().//// The data will have been collected into the current_reference string// by a call to process_alphanumeric().static boolprocess_special(){ CYG_REPORT_FUNCNAMETYPE("process_special", "special %d"); bool result = false; if ("to" == current_reference) { current_token = T_Range; result = true; } else if ("implies" == current_reference) { current_token = T_Implies; result = true; } else if ("xor" == current_reference) { current_token = T_Xor; result = true; } else if ("eqv" == current_reference) { current_token = T_Eqv; result = true; } else if (CdlFunction::is_function(current_reference.c_str(), current_function_id)) { current_token = T_Function; result = true; } if (result) { current_special = current_reference; current_reference = ""; } CYG_REPORT_RETVAL(result); return result;}//}}}//}}}//{{{ next_token() // ----------------------------------------------------------------------------// Work out what the next token is. This includes the handling of// strings, integers, doubles, and references.static voidnext_token(){ 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_special = ""; current_int = 0; current_double = 0.0; current_format = CdlValueFormat_Default; current_function_id = 0; // 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; case '.': current_token = T_StringConcat; next_char(); break; case ',': current_token = T_Comma; next_char(); break; default: // String constants have been handled already. The only // valid tokens that are left are numbers, references, // "specials" such as the range and string equality // operators, and functions. // // 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_alphanumeric(); if (!process_special()) { 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> ::= <implies> ? <conditional> : <conditional> | <implies>// <implies> ::= <eqv> [<implies op> <implies>] implies// <eqv> ::= <or> [<eqv op> <eqv>] xor, eqv // <or> ::= <and> [<or op> <or>] ||// <and> ::= <bitor> [<and op> <and>] &&// <bitor> ::= <bitxor> [<bitor op> <bitor>] |// <bitxor> ::= <bitand> [<bitxor op> <bitxor>] ^// <bitand> ::= <eq> [<bitand op> <and>] &// <eq> ::= <comp> [<eq op> <eq>] == !=// <comp> ::= <shift> [<comp op> <comp>] < <= > >=// <shift> ::= <add> [<shift op> <shift>] << >>// <add> ::= <mult> [<add op> <add>] + - .// <mult> ::= <unary> [<mult op> <mult>] * / %// <unary> ::= -<unary> | +<unary> | !<unary> | *<unary> | ?<unary> |// ~<unary> |// <string constant> | <integer constant> |// <double constant> | <reference> |// ( <expression> ) | <function>//// There are separate functions for each of these terms.// A forward declaration, needed for bracketed subexpressions.static void parse_expression(CdlExpression);// 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");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -