| /* |
| * expr_ruby.tc - Expression example treecc input file for Ruby. |
| * |
| * Copyright (C) 2001, 2002 Southern Storm Software, Pty Ltd. |
| * |
| * Hacked by Peter Minten <silvernerd@users.sf.net> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| %option lang = "Ruby" |
| |
| %output "expr_ruby.rb" |
| |
| /* |
| * Include the following declarations in the ".rb" file. |
| */ |
| %{ |
| |
| class Eval_value |
| Int_value = 0 |
| Float_value = 0 |
| end |
| |
| %} |
| |
| /* |
| * Define the type code that is associated with a node |
| * in the syntax tree. We use "error_type" to indicate |
| * a failure during type inferencing. |
| */ |
| %enum Type_code = |
| { |
| Error_type, |
| Int_type, |
| Float_type |
| } |
| |
| /* |
| * Define the node types that make up the syntax. |
| */ |
| %node Expression %abstract %typedef = |
| { |
| %nocreate Type_code type = {Type_code::Error_type}; |
| } |
| |
| %node Binary Expression %abstract = |
| { |
| Expression expr1; |
| Expression expr2; |
| } |
| |
| %node Unary Expression %abstract = |
| { |
| Expression expr; |
| } |
| |
| %node Intnum Expression = |
| { |
| int num; |
| } |
| |
| %node Floatnum Expression = |
| { |
| float num; |
| } |
| |
| %node Plus Binary |
| %node Minus Binary |
| %node Multiply Binary |
| %node Divide Binary |
| %node Power Binary |
| %node Negate Unary |
| |
| %node Cast Expression = |
| { |
| Type_code new_type; |
| Expression expr; |
| } |
| |
| /* |
| * Define the "infer_type" operation as a non-virtual. |
| */ |
| %operation void InferType::infer_type(Expression e) |
| |
| infer_type(Binary) |
| { |
| infer_type(e.expr1) |
| infer_type(e.expr2) |
| |
| if (e.expr1.type == Type_code::Error_type || e.expr2.type == Type_code::Error_type) then |
| e.type = Type_code::Error_type |
| elsif (e.expr1.type == Type_code::Float_type || e.expr2.type == Type_code::Float_type) then |
| e.type = Type_code::Float_type |
| else |
| e.type = Type_code::Int_type |
| end |
| } |
| |
| infer_type(Unary) |
| { |
| infer_type(e.expr) |
| e.type = e.expr.type |
| } |
| |
| infer_type(Intnum) |
| { |
| e.type = Type_code::Int_type |
| } |
| |
| infer_type(Floatnum) |
| { |
| e.type = Type_code::Float_type |
| } |
| |
| infer_type(Power) |
| { |
| infer_type(e.expr1) |
| infer_type(e.expr2) |
| |
| if (e.expr1.type == Type_code::Error_type || e.expr2.type == Type_code::Error_type) then |
| e.type = Type_code::Error_type |
| elsif (e.expr2.type != Type_code::Int_type) then |
| p (e.getFilename() + ":" + e.getLinenum() + ": second argument to `^' is not an integer") |
| e.type = Type_code::Error_type |
| else |
| e.type = e.expr1.type |
| end |
| } |
| |
| infer_type(Cast) |
| { |
| infer_type(e.expr) |
| |
| if(e.expr.type != Type_code::Error_type) |
| e.type = e.new_type |
| else |
| e.type = Type_code::Error_type |
| end |
| } |
| |
| /* |
| * Define the "eval_expr" operation as a virtual. |
| */ |
| %operation %virtual eval_value eval_expr(Expression this) |
| |
| eval_expr(Plus) |
| { |
| # Evaluate the sub-Expressions |
| eval_value value1 = expr1.eval_expr |
| eval_value value2 = expr2.eval_expr |
| |
| # Coerce to the common type |
| Coerce.coerce(value1, expr1.type, type) |
| Coerce.coerce(value2, expr2.type, type) |
| |
| # Evaluate the operator |
| if (type == Type_code::Int_type) then |
| value1.Int_value += value2.Int_value |
| else |
| value1.Float_value += value2.Float_value |
| end |
| |
| # Return the result to the caller |
| return value1 |
| } |
| |
| eval_expr(Minus) |
| { |
| # Evaluate the sub-Expressions |
| eval_value value1 = expr1.eval_expr() |
| eval_value value2 = expr2.eval_expr() |
| |
| # Coerce to the common type |
| Coerce.coerce(value1, expr1.type, type) |
| Coerce.coerce(value2, expr2.type, type) |
| |
| # Evaluate the operator |
| if(type == Type_code::Int_type) then |
| value1.Int_value -= value2.Int_value |
| else |
| value1.Float_value -= value2.Float_value; |
| end |
| |
| # Return the result to the caller |
| return value1 |
| } |
| |
| eval_expr(Multiply) |
| { |
| # Evaluate the sub-Expressions |
| eval_value value1 = expr1.eval_expr() |
| eval_value value2 = expr2.eval_expr() |
| |
| # Coerce to the common type |
| Coerce.coerce(value1, expr1.type, type) |
| Coerce.coerce(value2, expr2.type, type) |
| |
| # Evaluate the operator |
| if(type == Type_code::Int_type) then |
| value1.Int_value *= value2.Int_value |
| else |
| value1.Float_value *= value2.Float_value; |
| end |
| |
| # Return the result to the caller |
| return value1 |
| } |
| |
| eval_expr(Divide) |
| { |
| # Evaluate the sub-Expressions |
| eval_value value1 = expr1.eval_expr() |
| eval_value value2 = expr2.eval_expr() |
| |
| # Coerce to the common type |
| Coerce.coerce(value1, expr1.type, type) |
| Coerce.coerce(value2, expr2.type, type) |
| |
| # Evaluate the operator |
| if(type == Type_code::Int_type) then |
| value1.Int_value -= value2.Int_value |
| else |
| value1.Float_value -= value2.Float_value; |
| end |
| |
| # Return the result to the caller |
| return value1 |
| } |
| |
| eval_expr(Power) |
| { |
| # Evaluate the sub-Expressions |
| eval_value value1 = expr1.eval_expr() |
| eval_value value2 = expr2.eval_expr() |
| |
| # Coerce to the common type |
| Coerce.coerce(value1, expr1.type, type) |
| Coerce.coerce(value2, expr2.type, type) |
| |
| # Evaluate the operator |
| if(type == Type_code::Int_type) then |
| value1.Int_value = value1.Int_value ^ value2.Int_value |
| else |
| value1.Float_value = value1.Float_value ^ value2.Float_value; |
| end |
| |
| # Return the result to the caller |
| return value1 |
| } |
| |
| eval_expr(Negate) |
| { |
| # Evaluate the sub-Expression |
| eval_value value = expr.eval_expr() |
| |
| # Coerce to the common type |
| Coerce.coerce(value1, expr1.type, type) |
| Coerce.coerce(value, expr.type, type) |
| |
| # Evaluate the operator |
| if(type == Type_code::Int_type) then |
| value.Int_value = -1 * value.Int_value |
| else |
| value.Float_value = -1 * value.Float_value; |
| end |
| |
| # Return the result to the caller |
| return value |
| } |
| |
| eval_expr(Cast) |
| { |
| # Evaluate the sub-Expression |
| eval_value value = expr.eval_expr() |
| |
| # Coerce to the common type |
| Coerce.coerce(value, expr.type, type) |
| |
| # Return the result to the caller |
| return value |
| } |
| |
| eval_expr(Intnum) |
| { |
| value = eval_value.new |
| value.Int_value = num |
| return value |
| } |
| |
| eval_expr(Floatnum) |
| { |
| value = eval_value.new |
| value.Float_value = num |
| return value |
| } |
| |
| /* |
| * Define the "coerce" operation as an inline non-virtual. |
| */ |
| %operation %inline void Coerce::coerce |
| (value, [Type_code from], [Type_code to]) |
| |
| coerce(Int_type, Float_type) |
| { |
| value.Float_value = value.Int_value.to_f; |
| } |
| |
| coerce(Float_type, Int_type) |
| { |
| value.Int_value = value.Float_value.to_i; |
| } |
| |
| coerce(Type_code, Type_code) |
| { |
| # Nothing to do here |
| } |