📄 expr.cc
字号:
// $Header: /cvsroot/sourcenav/src/snavigator/demo/c++_demo/glish/Expr.cc,v 1.1.1.1 2002/04/18 23:35:24 mdejong Exp $#include <stream.h>#include <string.h>#include <stdlib.h>#include "Reporter.h"#include "Sequencer.h"#include "Expr.h"#include "Agent.h"#include "Func.h"void Expr::SideEffectsEval() { const Value* v = ReadOnlyEval(); if ( v ) { glish_type t = v->Type(); ReadOnlyDone( v ); if ( t != TYPE_FUNC ) warn->Report( "expression value ignored:", this ); } }Value* Expr::RefEval( value_type val_type ) { Value* value = CopyEval(); Value* result; if ( val_type == VAL_VAL ) { result = value; Ref( value ); } else result = new Value( value, val_type ); if ( val_type == VAL_REF && value->IsConst() ) warn->Report( "\"const\" reference converted to \"ref\" in", this ); Unref( value ); // result is now the only pointer to value return result; }void Expr::Assign( Value* /* new_value */ ) { error->Report( this, "is not a valid target for assignment" ); }int Expr::Invisible() const { return 0; }Value* Expr::CopyOrRefValue( const Value* value, eval_type etype ) { if ( etype == EVAL_COPY ) return copy_value( value ); else if ( etype == EVAL_READ_ONLY ) { Value* result = (Value*) value; Ref( result ); return result; } else { // EVAL_SIDE_EFFECTS should've been caught earlier; making it // this far indicates that the function erroneously overrode // SideEffectsEval(). fatal->Report( "bad eval_type in Expr::CopyOrRefValue" ); return 0; } }VarExpr::VarExpr( char* var_id, scope_type var_scope, int var_offset, Sequencer* var_sequencer ) : Expr(var_id) { id = var_id; scope = var_scope; frame_offset = var_offset; sequencer = var_sequencer; }VarExpr::~VarExpr() { delete id; }Value* VarExpr::Eval( eval_type etype ) { Value* value = sequencer->FrameElement( scope, frame_offset ); if ( ! value ) { warn->Report( "uninitialized variable", this, "used" ); value = error_value(); sequencer->SetFrameElement( scope, frame_offset, value ); } value = value->Deref(); return CopyOrRefValue( value, etype ); }Value* VarExpr::RefEval( value_type val_type ) { Value* var = sequencer->FrameElement( scope, frame_offset ); if ( ! var ) { // Presumably we're going to be assigning to a subelement. var = new Value( glish_false ); sequencer->SetFrameElement( scope, frame_offset, var ); } if ( val_type == VAL_VAL ) return copy_value( var ); if ( val_type == VAL_REF && var->IsConst() ) warn->Report( this, " is a \"const\" reference" ); return new Value( var, val_type ); }void VarExpr::Assign( Value* new_value ) { sequencer->SetFrameElement( scope, frame_offset, new_value ); }Value* ValExpr::Eval( eval_type etype ) { return CopyOrRefValue( val, etype ); }Value* ValExpr::RefEval( value_type val_type ) { if ( val_type == VAL_REF && val->IsConst() ) warn->Report( this, " is a \"const\" reference" ); return new Value( val, val_type ); }ConstExpr::ConstExpr( const Value* value ) : Expr("constant") { const_value = value; }Value* ConstExpr::Eval( eval_type etype ) { return CopyOrRefValue( const_value, etype ); }void ConstExpr::DescribeSelf( ostream& s ) const { const_value->DescribeSelf( s ); }UnaryExpr::UnaryExpr( Expr* operand, const char* desc ) : Expr(desc) { op = operand; }void UnaryExpr::Describe( ostream& s ) const { DescribeSelf( s ); op->Describe( s ); }BinaryExpr::BinaryExpr( Expr* op1, Expr* op2, const char* desc ) : Expr(desc) { left = op1; right = op2; }void BinaryExpr::Describe( ostream& s ) const { s << "("; left->Describe( s ); s << " "; DescribeSelf( s ); s << " "; right->Describe( s ); s << ")"; }NegExpr::NegExpr( Expr* operand ) : UnaryExpr( operand, "-" ) { }Value* NegExpr::Eval( eval_type /* etype */ ) { Value* result = op->CopyEval(); result->Negate(); return result; }NotExpr::NotExpr( Expr* operand ) : UnaryExpr( operand, "!" ) { }Value* NotExpr::Eval( eval_type /* etype */ ) { Value* result = op->CopyEval(); result->Not(); return result; }AssignExpr::AssignExpr( Expr* op1, Expr* op2 ) : BinaryExpr(op1, op2, ":=") { }Value* AssignExpr::Eval( eval_type etype ) { left->Assign( right->CopyEval() ); if ( etype == EVAL_COPY ) return left->CopyEval(); else if ( etype == EVAL_READ_ONLY ) return (Value*) left->ReadOnlyEval(); else return 0; }void AssignExpr::SideEffectsEval() { if ( Eval( EVAL_SIDE_EFFECTS ) ) fatal->Report( "value unexpected returnedly in AssignExpr::SideEffectsEval" ); }int AssignExpr::Invisible() const { return 1; }OrExpr::OrExpr( Expr* op1, Expr* op2 ) : BinaryExpr(op1, op2, "||") { }Value* OrExpr::Eval( eval_type etype ) { const Value* left_value = left->ReadOnlyEval(); if ( left_value->BoolVal() ) { if ( etype == EVAL_COPY ) { Value* result = copy_value( left_value ); left->ReadOnlyDone( left_value ); return result; } else return (Value*) left_value; } else return right->Eval( etype ); }AndExpr::AndExpr( Expr* op1, Expr* op2 ) : BinaryExpr(op1, op2, "&&") { }Value* AndExpr::Eval( eval_type etype ) { const Value* left_value = left->ReadOnlyEval(); int left_is_true = left_value->BoolVal(); left->ReadOnlyDone( left_value ); if ( etype == EVAL_COPY ) { if ( left_is_true ) return right->CopyEval(); else return new Value( glish_false ); } else { if ( left_is_true ) return (Value*) right->ReadOnlyEval(); else return new Value( glish_false ); } }ConstructExpr::ConstructExpr( parameter_list* arg_args ) : Expr("[construct]") { is_array_constructor = 1; args = arg_args; if ( args ) { loop_over_list( *args, i ) { if ( (*args)[i]->Name() ) { if ( i > 0 && is_array_constructor ) { error->Report( "mixed array/record constructor: ", this ); break; } is_array_constructor = 0; } else if ( ! is_array_constructor ) { error->Report( "mixed array/record constructor: ", this ); is_array_constructor = 1; break; } } } }Value* ConstructExpr::Eval( eval_type /* etype */ ) { if ( ! args ) return create_record(); else if ( args->length() == 0 ) return empty_value(); else if ( is_array_constructor ) return BuildArray(); else return BuildRecord(); }void ConstructExpr::Describe( ostream& s ) const { s << "["; if ( args ) describe_parameter_list( args, s ); else s << "="; s << "]"; }Value* ConstructExpr::BuildArray() { Value* result; typedef const Value* const_value_ptr; int num_values = 0; loop_over_list( *args, i ) { Parameter* arg = (*args)[i]; if ( arg->IsEllipsis() ) num_values += (*args)[i]->NumEllipsisVals(); else ++num_values; } const_value_ptr* values = new const_value_ptr[num_values]; int total_length = 0; for ( i = 0; i < args->length(); ++i ) { Parameter* arg = (*args)[i]; if ( arg->IsEllipsis() ) { int len = arg->NumEllipsisVals(); for ( int j = 0; j < len; ++j ) { values[i+j] = arg->NthEllipsisVal(j)->Deref(); total_length += values[i+j]->Length(); } } else { values[i] = arg->Arg()->ReadOnlyEval(); total_length += values[i]->Length(); } } glish_type max_type; if ( TypeCheck( values, num_values, max_type ) ) result = ConstructArray( values, num_values, total_length, max_type ); else result = error_value(); for ( i = 0; i < args->length(); ++i ) if ( ! (*args)[i]->IsEllipsis() ) (*args)[i]->Arg()->ReadOnlyDone( values[i] ); delete values; return result; }int ConstructExpr::TypeCheck( const Value* values[], int num_values, glish_type& max_type ) { if ( num_values == 0 ) { max_type = TYPE_BOOL; // Compatible with the constant F return 1; } for ( int i = 0; i < num_values; ++i ) { const Value* v = values[i]; if ( v->Length() > 0 && v->IsNumeric() ) return MaxNumeric( values, num_values, max_type ); } int result = AllEquivalent( values, num_values, max_type ); if ( max_type == TYPE_RECORD ) { error->Report( "arrays of records are not supported" ); return 0; } return result; }int ConstructExpr::MaxNumeric( const Value* values[], int num_values, glish_type& max_type ) { const Value* v = values[0]->VecRefDeref(); if ( ! v->IsNumeric() ) { error->Report( "non-numeric type in array constructor", this ); return 0; } max_type = v->Type(); for ( int i = 1; i < num_values; ++i ) { v = values[i]->VecRefDeref(); if ( ! v->IsNumeric() ) { error->Report( "non-numeric type in array constructor", this ); return 0; } max_type = max_numeric_type( v->Type(), max_type ); } return 1; }int ConstructExpr::AllEquivalent( const Value* values[], int num_values, glish_type& max_type ) { max_type = TYPE_BOOL; // First pick a candidate type. for ( int i = 0; i < num_values; ++i ) // Ignore empty arrays, as they can be any type. if ( values[i]->Length() > 0 ) { max_type = values[i]->VecRefDeref()->Type(); break; } // Now check whether all non-empty arrays conform to that type. for ( i = 0; i < num_values; ++i ) { const Value* v = values[i]->VecRefDeref(); if ( v->Length() > 0 && v->Type() != max_type ) { error->Report( "incompatible types in array constructor", this ); return 0; } } return 1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -