📄 expr.c
字号:
* 'foo-foo' symbol references cancelled to 0, * which changes X_seg from SEG_DIFFERENCE to SEG_ABSOLUTE; * Unused fields zeroed to help expr(). */static voidclean_up_expression (expressionP) register expressionS * expressionP;{ switch (expressionP -> X_seg) { case SEG_NONE: case SEG_PASS1: expressionP -> X_add_symbol = NULL; expressionP -> X_subtract_symbol = NULL; expressionP -> X_add_number = 0; break; case SEG_BIG: case SEG_ABSOLUTE: expressionP -> X_subtract_symbol = NULL; expressionP -> X_add_symbol = NULL; break; case SEG_TEXT: case SEG_DATA: case SEG_BSS: case SEG_UNKNOWN: expressionP -> X_subtract_symbol = NULL; break; case SEG_DIFFERENCE: /* * It does not hurt to 'cancel' NULL==NULL * when comparing symbols for 'eq'ness. * It is faster to re-cancel them to NULL * than to check for this special case. */ if (expressionP -> X_subtract_symbol == expressionP -> X_add_symbol || ( expressionP->X_subtract_symbol && expressionP->X_add_symbol && expressionP->X_subtract_symbol->sy_frag==expressionP->X_add_symbol->sy_frag && expressionP->X_subtract_symbol->sy_value==expressionP->X_add_symbol->sy_value)) { expressionP -> X_subtract_symbol = NULL; expressionP -> X_add_symbol = NULL; expressionP -> X_seg = SEG_ABSOLUTE; } break; default: BAD_CASE( expressionP -> X_seg); break; }}/* * expr_part () * * Internal. Made a function because this code is used in 2 places. * Generate error or correct X_?????_symbol of expressionS. *//* * symbol_1 += symbol_2 ... well ... sort of. */static segTexpr_part (symbol_1_PP, symbol_2_P) struct symbol ** symbol_1_PP; struct symbol * symbol_2_P;{ segT return_value; know( (* symbol_1_PP) == NULL || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_TEXT || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_DATA || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_BSS || ((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF ); know( symbol_2_P == NULL || (symbol_2_P -> sy_type & N_TYPE) == N_TEXT || (symbol_2_P -> sy_type & N_TYPE) == N_DATA || (symbol_2_P -> sy_type & N_TYPE) == N_BSS || (symbol_2_P -> sy_type & N_TYPE) == N_UNDF ); if (* symbol_1_PP) { if (((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF) { if (symbol_2_P) { return_value = SEG_PASS1; * symbol_1_PP = NULL; } else { know( ((* symbol_1_PP) -> sy_type & N_TYPE) == N_UNDF) return_value = SEG_UNKNOWN; } } else { if (symbol_2_P) { if ((symbol_2_P -> sy_type & N_TYPE) == N_UNDF) { * symbol_1_PP = NULL; return_value = SEG_PASS1; } else { /* {seg1} - {seg2} */ as_warn( "Expression too complex, 2 symbols forgotten: \"%s\" \"%s\"", (* symbol_1_PP) -> sy_name, symbol_2_P -> sy_name ); * symbol_1_PP = NULL; return_value = SEG_ABSOLUTE; } } else { return_value = N_TYPE_seg [(* symbol_1_PP) -> sy_type & N_TYPE]; } } } else { /* (* symbol_1_PP) == NULL */ if (symbol_2_P) { * symbol_1_PP = symbol_2_P; return_value = N_TYPE_seg [(symbol_2_P) -> sy_type & N_TYPE]; } else { * symbol_1_PP = NULL; return_value = SEG_ABSOLUTE; } } know( return_value == SEG_ABSOLUTE || return_value == SEG_TEXT || return_value == SEG_DATA || return_value == SEG_BSS || return_value == SEG_UNKNOWN || return_value == SEG_PASS1 ); know( (* symbol_1_PP) == NULL || ((* symbol_1_PP) -> sy_type & N_TYPE) == seg_N_TYPE [(int) return_value] ); return (return_value);} /* expr_part() *//* Expression parser. *//* * We allow an empty expression, and just assume (absolute,0) silently. * Unary operators and parenthetical expressions are treated as operands. * As usual, Q==quantity==operand, O==operator, X==expression mnemonics. * * We used to do a aho/ullman shift-reduce parser, but the logic got so * warped that I flushed it and wrote a recursive-descent parser instead. * Now things are stable, would anybody like to write a fast parser? * Most expressions are either register (which does not even reach here) * or 1 symbol. Then "symbol+constant" and "symbol-symbol" are common. * So I guess it doesn't really matter how inefficient more complex expressions * are parsed. * * After expr(RANK,resultP) input_line_pointer -> operator of rank <= RANK. * Also, we have consumed any leading or trailing spaces (operand does that) * and done all intervening operators. */typedef enum{O_illegal, /* (0) what we get for illegal op */O_multiply, /* (1) * */O_divide, /* (2) / */O_modulus, /* (3) % */O_left_shift, /* (4) < */O_right_shift, /* (5) > */O_bit_inclusive_or, /* (6) | */O_bit_or_not, /* (7) ! */O_bit_exclusive_or, /* (8) ^ */O_bit_and, /* (9) & */O_add, /* (10) + */O_subtract /* (11) - */}operatorT;#define __ O_illegalstatic const operatorT op_encoding [256] = { /* maps ASCII -> operators */__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,__, O_bit_or_not, __, __, __, O_modulus, O_bit_and, __,__, __, O_multiply, O_add, __, O_subtract, __, O_divide,__, __, __, __, __, __, __, __,__, __, __, __, O_left_shift, __, O_right_shift, __,__, __, __, __, __, __, __, __,__, __, __, __, __, __, __, __,__, __, __, __, __, __, __, __,__, __, __, __, __, __, O_bit_exclusive_or, __,__, __, __, __, __, __, __, __,__, __, __, __, __, __, __, __,__, __, __, __, __, __, __, __,__, __, __, __, O_bit_inclusive_or, __, __, __,__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __};/* * Rank Examples * 0 operand, (expression) * 1 + - * 2 & ^ ! | * 3 * / % < > */typedef char operator_rankT;static const operator_rankTop_rank [] = { 0, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1 };segT /* Return resultP -> X_seg. */expr (rank, resultP) register operator_rankT rank; /* Larger # is higher rank. */ register expressionS * resultP; /* Deliver result here. */{ expressionS right; register operatorT op_left; register char c_left; /* 1st operator character. */ register operatorT op_right; register char c_right; know( rank >= 0 ); (void)operand (resultP); know( * input_line_pointer != ' ' ); /* Operand() gobbles spaces. */ c_left = * input_line_pointer; /* Potential operator character. */ op_left = op_encoding [c_left]; while (op_left != O_illegal && op_rank [(int) op_left] > rank) { input_line_pointer ++; /* -> after 1st character of operator. */ /* Operators "<<" and ">>" have 2 characters. */ if (* input_line_pointer == c_left && (c_left == '<' || c_left == '>') ) { input_line_pointer ++; } /* -> after operator. */ if (SEG_NONE == expr (op_rank[(int) op_left], &right)) { as_warn("Missing operand value assumed absolute 0."); resultP -> X_add_number = 0; resultP -> X_subtract_symbol = NULL; resultP -> X_add_symbol = NULL; resultP -> X_seg = SEG_ABSOLUTE; } know( * input_line_pointer != ' ' ); c_right = * input_line_pointer; op_right = op_encoding [c_right]; if (* input_line_pointer == c_right && (c_right == '<' || c_right == '>') ) { input_line_pointer ++; } /* -> after operator. */ know( (int) op_right == 0 || op_rank [(int) op_right] <= op_rank[(int) op_left] ); /* input_line_pointer -> after right-hand quantity. */ /* left-hand quantity in resultP */ /* right-hand quantity in right. */ /* operator in op_left. */ if ( resultP -> X_seg == SEG_PASS1 || right . X_seg == SEG_PASS1 ) { resultP -> X_seg = SEG_PASS1; } else { if ( resultP -> X_seg == SEG_BIG ) { as_warn( "Left operand of %c is a %s. Integer 0 assumed.", c_left, resultP -> X_add_number > 0 ? "bignum" : "float"); resultP -> X_seg = SEG_ABSOLUTE; resultP -> X_add_symbol = 0; resultP -> X_subtract_symbol = 0; resultP -> X_add_number = 0; } if ( right . X_seg == SEG_BIG ) { as_warn( "Right operand of %c is a %s. Integer 0 assumed.", c_left, right . X_add_number > 0 ? "bignum" : "float"); right . X_seg = SEG_ABSOLUTE; right . X_add_symbol = 0; right . X_subtract_symbol = 0; right . X_add_number = 0; } if ( op_left == O_subtract ) { /* * Convert - into + by exchanging symbols and negating number. * I know -infinity can't be negated in 2's complement: * but then it can't be subtracted either. This trick * does not cause any further inaccuracy. */ register struct symbol * symbolP; right . X_add_number = - right . X_add_number; symbolP = right . X_add_symbol; right . X_add_symbol = right . X_subtract_symbol; right . X_subtract_symbol = symbolP; if (symbolP) { right . X_seg = SEG_DIFFERENCE; } op_left = O_add; } if ( op_left == O_add ) { segT seg1; segT seg2; know( resultP -> X_seg == SEG_DATA || resultP -> X_seg == SEG_TEXT || resultP -> X_seg == SEG_BSS || resultP -> X_seg == SEG_UNKNOWN || resultP -> X_seg == SEG_DIFFERENCE || resultP -> X_seg == SEG_ABSOLUTE || resultP -> X_seg == SEG_PASS1 ); know( right . X_seg == SEG_DATA || right . X_seg == SEG_TEXT || right . X_seg == SEG_BSS || right . X_seg == SEG_UNKNOWN || right . X_seg == SEG_DIFFERENCE || right . X_seg == SEG_ABSOLUTE || right . X_seg == SEG_PASS1 ); clean_up_expression (& right); clean_up_expression (resultP); seg1 = expr_part (& resultP -> X_add_symbol, right . X_add_symbol); seg2 = expr_part (& resultP -> X_subtract_symbol, right . X_subtract_symbol); if (seg1 == SEG_PASS1 || seg2 == SEG_PASS1) { need_pass_2 = TRUE; resultP -> X_seg = SEG_PASS1; } else if (seg2 == SEG_ABSOLUTE) resultP -> X_seg = seg1; else if ( seg1 != SEG_UNKNOWN && seg1 != SEG_ABSOLUTE && seg2 != SEG_UNKNOWN && seg1 != seg2) { know( seg2 != SEG_ABSOLUTE ); know( resultP -> X_subtract_symbol ); know( seg1 == SEG_TEXT || seg1 == SEG_DATA || seg1== SEG_BSS ); know( seg2 == SEG_TEXT || seg2 == SEG_DATA || seg2== SEG_BSS ); know( resultP -> X_add_symbol ); know( resultP -> X_subtract_symbol ); as_warn("Expression too complex: forgetting %s - %s", resultP -> X_add_symbol -> sy_name, resultP -> X_subtract_symbol -> sy_name); resultP -> X_seg = SEG_ABSOLUTE; /* Clean_up_expression() will do the rest. */ } else resultP -> X_seg = SEG_DIFFERENCE; resultP -> X_add_number += right . X_add_number; clean_up_expression (resultP); } else { /* Not +. */ if ( resultP -> X_seg == SEG_UNKNOWN || right . X_seg == SEG_UNKNOWN ) { resultP -> X_seg = SEG_PASS1; need_pass_2 = TRUE; } else { resultP -> X_subtract_symbol = NULL; resultP -> X_add_symbol = NULL; /* Will be SEG_ABSOLUTE. */ if ( resultP -> X_seg != SEG_ABSOLUTE || right . X_seg != SEG_ABSOLUTE ) { as_warn( "Relocation error. Absolute 0 assumed."); resultP -> X_seg = SEG_ABSOLUTE; resultP -> X_add_number = 0; } else { switch ( op_left ) { case O_bit_inclusive_or: resultP -> X_add_number |= right . X_add_number; break; case O_modulus: if (right . X_add_number) { resultP -> X_add_number %= right . X_add_number; } else { as_warn( "Division by 0. 0 assumed." ); resultP -> X_add_number = 0; } break; case O_bit_and: resultP -> X_add_number &= right . X_add_number; break; case O_multiply: resultP -> X_add_number *= right . X_add_number; break; case O_divide: if (right . X_add_number) { resultP -> X_add_number /= right . X_add_number; } else { as_warn( "Division by 0. 0 assumed." ); resultP -> X_add_number = 0; } break; case O_left_shift: resultP -> X_add_number <<= right . X_add_number; break; case O_right_shift: resultP -> X_add_number >>= right . X_add_number; break; case O_bit_exclusive_or: resultP -> X_add_number ^= right . X_add_number; break; case O_bit_or_not: resultP -> X_add_number |= ~ right . X_add_number; break; default: BAD_CASE( op_left ); break; } /* switch(operator) */ } } /* If we have to force need_pass_2. */ } /* If operator was +. */ } /* If we didn't set need_pass_2. */ op_left = op_right; } /* While next operator is >= this rank. */ return (resultP -> X_seg);}/* * get_symbol_end() * * This lives here because it belongs equally in expr.c & read.c. * Expr.c is just a branch office read.c anyway, and putting it * here lessens the crowd at read.c. * * Assume input_line_pointer is at start of symbol name. * Advance input_line_pointer past symbol name. * Turn that character into a '\0', returning its former value. * This allows a string compare (RMS wants symbol names to be strings) * of the symbol name. * There will always be a char following symbol name, because all good * lines end in end-of-line. */charget_symbol_end(){ register char c; while ( is_part_of_name( c = * input_line_pointer ++ ) ) ; * -- input_line_pointer = 0; return (c);}/* end: expr.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -