home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 27 / IOPROG_27.ISO / SOFT / CALCPLUS.ZIP / YYCALC.YAC < prev   
Encoding:
Text File  |  1996-04-02  |  16.8 KB  |  562 lines

  1. /*******************************************************
  2.  
  3.     The CalcPlus Class Library Version 1.0,
  4.     Author: Vladimir Schipunov, Copyright (C) 1996
  5.  
  6.     This library is free software. Permission to use,
  7.     copy, modify and redistribute the CalcPlus library
  8.     for any purpose is hereby granted without fee,
  9.     provided that the above copyright notice appear
  10.     in all copies.
  11.  
  12. *******************************************************/
  13.  
  14. %{
  15. //#define YYDEBUG
  16. #include <iostream.h>
  17. #include <stdarg.h>
  18. #include <stdio.h>
  19. #include "yycalc.h"
  20. #include "calcexpr.h"
  21. #include "calctype.h"
  22. class Expression;
  23. #define yyparse CalcPlus::yyparse
  24.  
  25. #define XSEQ ((XBlock*)(Blocks.Last()))
  26. #define XBEG {XBlock *x = new XBlock; Blocks.Push(x);}
  27. #define XEND {Blocks.Pop();}
  28. #define COND(x) ((XBlock*)(Cond##x.Last()))
  29. #define YYMAXDEPTH 100
  30. %}
  31.  
  32. %union {
  33.     char    c;
  34.     long    i;
  35.     double  r;
  36.     char*   s;
  37.     Var*    v;
  38.     CArray* a;
  39.     XFunction*  f;
  40.     Expression* e;
  41.     XVariable*  x;
  42. }
  43.  
  44. /*
  45.     Note that lexical analizer returns "lx***" for simple
  46.     lexical tokens and "yy***" if symbol is already declared.
  47. */
  48.  
  49. %token  lxInt   lxReal  lxName  lxVar   lxStep  lxAssign
  50. %token  lxFunc  lxGe    lxLe    lxNe    lxEcho  lxStruct
  51. %token  lxNot   lxOr    lxAnd   lxImp   lxIf    lxThen
  52. %token  lxElse  lxEndl  lxTrue  lxFalse lxNil   lxBegin
  53. %token  lxEnd   lxWhile lxDo    lxFor   lxTo    lxInclude
  54. %token  lxRet   lxExit  lxConst lxUser  lxLoop  lxString
  55. %token  lxProc  lxInc   lxDec   lxIfdef lxEndif lxDefine
  56. %token  lxUndef lxIfndef
  57. %token  yyVar   yyFunc  yyProc  yyConst yyStruct
  58.  
  59. %right      lxAssign
  60. %left       lxImp
  61. %left       lxOr
  62. %left       lxAnd
  63. %right      lxNot '!'
  64. %nonassoc   '<' lxLe '>' lxGe lxNe '='
  65. %left       '+' '-'
  66. %left       '*' '/'
  67. %left       '^'
  68.  
  69. %type <i>   lxInt step
  70. %type <r>   lxReal
  71. %type <s>   lxString lxName varname
  72. %type <v>   yyVar yyConst varcnst vardecl
  73. %type <f>   yyFunc yyProc declf extern fname func
  74. %type <e>   term stat assign expr boolean booltmp
  75. %type <e>   callf callp block ret lxUser array idx
  76. %type <a>   yyStruct
  77. %type <x>   var const
  78.  
  79. /*
  80.     Here is the short description of the language.
  81.     I hope most of the syntax is clear because
  82.     language looks like other procedure languages.
  83.     Basicly syntax is:
  84.  
  85.     Block:
  86.             begin
  87.                 ...
  88.             end;
  89.  
  90.     Variables:
  91.  
  92.             var x,y;
  93.  
  94.             var a:=2*3;
  95.  
  96.             const c:=1;
  97.  
  98.             struct abc {a,b,c};
  99.             abc abc_var;
  100.  
  101.     Funcs, procs:
  102.  
  103.             function f(x,y)
  104.                 ...
  105.             end;
  106.  
  107.     Conditions:
  108.  
  109.             if expr then
  110.                 ...
  111.             else
  112.                 ...
  113.             end;
  114.  
  115.             expr1 -> expr2;
  116.  
  117.     Loops:
  118.  
  119.             while expr do
  120.                 ...
  121.                 [loop]      // like continue in C
  122.                 ...
  123.                 [exit]      // like break in C
  124.                 ...
  125.             end;
  126.             
  127.             for i:=expr1 to expr2 [step expr3] do
  128.                 ...
  129.             end;
  130.  
  131.     Output:
  132.  
  133.             echo exprlist;
  134. */
  135.  
  136. %start module
  137. %%
  138. module  :
  139.         |   module decl varlist';'{}
  140.         |   module struct';'      {}
  141.         |   module extern';'      {}
  142.         |   module func           {}
  143.         |   module lxName  { yyerror( "unknown symbol ", $2 ); yyerrok; }
  144.         |   module error';'{ yyerror(); yyerrok; }
  145.         ;
  146. block   :   lxBegin { XBEG; } stats lxEnd { $$ = XSEQ; XEND; }
  147.         ;
  148. decl    :   lxVar    { DeclType = declVar;   StructTmp = 0; } declstr {}
  149.         |   lxConst  { DeclType = declConst; StructTmp = 0; } declstr {}
  150.         |   yyStruct { DeclType = declVar;   StructTmp = $1;}
  151.         ;
  152. declstr :   {}
  153.         |   yyStruct { StructTmp = $1; }
  154.         ;
  155. stats   :
  156.         |   stats decl varlist';'{}
  157.         |   stats struct';' {}
  158.         |   stats ';'       {}
  159.         |   stats stat ';'  { XSEQ->Add( $2 ); }
  160.         |   stats error';'  { yyerror(); yyerrok; }
  161.         |   stats lxName    { yyerror( "unknown symbol ", $2 ); yyerrok; }
  162.         ;
  163. stat    :   block   { $$ = $1; }
  164.         |   callp   { $$ = $1; }
  165.         |   callf   { $$ = $1; }
  166.         |   assign  { $$ = $1; }
  167.         |   ret     { $$ = $1; }
  168.         |   lxExit  { $$ = new XBreak; }
  169.         |   lxLoop  { $$ = new XLoop; }
  170.         |   lxEcho  { EchoTmp = new XEcho;}
  171.             echoes  { $$ = EchoTmp; }
  172.         |   boolean lxImp stat { $$ = new XConditional( $1, $3 ); }
  173.         |   lxIf booltmp lxThen stats lxEnd
  174.             {
  175.                 $$ = new XConditional( $2, XSEQ );
  176.                 XEND;
  177.                 Cond1.Pop();
  178.             }
  179.         |   lxIf booltmp lxThen stats
  180.             lxElse
  181.             {
  182.                 XEND;
  183.                 XBEG;
  184.                 Cond2.Push( XSEQ );
  185.             } stats lxEnd
  186.             {
  187.                 XEND;
  188.                 $$ = new XConditional( $2, COND(1), COND(2));
  189.                 Cond1.Pop();
  190.                 Cond2.Pop();
  191.             }
  192.         |   lxWhile boolean lxDo { XBEG; } stats lxEnd
  193.             {
  194.                 $$ = new XWhile( $2, XSEQ );
  195.                 XEND;
  196.             }
  197.         |   lxFor yyVar lxAssign expr lxTo expr step lxDo { XBEG; } stats lxEnd
  198.             {
  199.                 XBlock *x = XSEQ;
  200.                 XEND;
  201.                 XSEQ->Add(( new XVariable( $2 ))->Add( $4 ));
  202.                 $$ = new XWhile( new XComparison( new XVariable( $2 ),'{', $6 ),
  203.                     x, (new XVariable( $2 ))->Add( new XAr2( new XVariable( $2 ),
  204.                         '+',new XImmediate( new CLong( $7 )))));
  205.             }
  206.         |   lxFor '(' stat ';' expr ';' stat ')' { XBEG; } stats lxEnd
  207.             {
  208.                 XBlock *x = XSEQ;
  209.                 XEND;
  210.                 XSEQ->Add( $3 );
  211.                 $$ = new XWhile( $5, x, $7 );
  212.             }
  213.         |   yyVar lxInc { $$ = (new XVariable( $1 ))->Add(
  214.                 new XAr2( new XVariable( $1 ), '+',
  215.                     new XImmediate( new CLong( 1 )))); }
  216.         ;
  217. booltmp :   boolean { XBEG; Cond1.Push( XSEQ ); $$ = $1; }
  218.         ;
  219. ret     :   lxRet       { $$ = new XReturn; }
  220.         |   lxRet expr  { $$ = new XReturn( $2 ); }
  221.         ;
  222. step    :                   { $$ =  1; }
  223.         |   lxStep  lxInt   { $$ = $2; }
  224.         ;
  225. echoes  :   expr            { EchoTmp->Add( $1 ); }
  226.         |   echoes','expr   { EchoTmp->Add( $3 ); }
  227.         ;
  228. varlist :   vardecl             {}
  229.         |   varlist','vardecl   {}
  230.         ;
  231. vardecl :   varname         { AddVar( $1 ); }
  232.         |   varname         { VarTmp = AddVar( $1 ); }
  233.             lxAssign expr   { XSEQ->Add(( new XVariable( VarTmp ))->Add( $4 ));}
  234.         ;
  235. varname :   lxName          { $$ = $1; }
  236.         |   varcnst         { $$ = $1->name;if(XSEQ->vars($1->name)){yyerrok;
  237.                               yyerror("variable ", $1->name," already exist"); }}
  238.         ;
  239. varcnst :   yyVar           { $$ = $1; }
  240.         |   yyConst         { $$ = $1; }
  241.         ;
  242. assign  :   var lxAssign expr {( $$ = $1 )->Add( $3 ); }
  243.         |   lxUser lxAssign expr{ $$ = UserSym( $1, $3 );  }
  244.         ;
  245. struct  :   lxStruct lxName
  246.             {
  247.                 HideVars = 1;
  248.                 StructTmp = new CArray;
  249.                 XSEQ->structs.Add( new LexStruct( $2,
  250.                     StructTmp, yyStruct ));
  251.             }
  252.             '{' strings '}' { HideVars = 0; }
  253.         ;
  254. strings :   lxName              { StructTmp->add( new CString( $1 )); }
  255.         |   strings','lxName    { StructTmp->add( new CString( $3 )); }
  256.         ;
  257. expr    :   term                { $$ = $1; }
  258.         |   expr'+'expr         { $$ = new XAr2( $1, '+', $3 ); }
  259.         |   expr'-'expr         { $$ = new XAr2( $1, '-', $3 ); }
  260.         |   expr'*'expr         { $$ = new XAr2( $1, '*', $3 ); }
  261.         |   expr'/'expr         { $$ = new XAr2( $1, '/', $3 ); }
  262.         |   '+'term %prec '*'   { $$ = new XAr1( '+', $2 ); }
  263.         |   '-'term %prec '*'   { $$ = new XAr1( '-', $2 ); }
  264.         ;
  265. expr    :   '!' expr            { $$ = new XBool1( $2 ); }
  266.         |   lxNot expr          { $$ = new XBool1( $2 ); }
  267.         |   expr lxOr expr      { $$ = new XBool2( $1, '|', $3 ); }
  268.         |   expr lxAnd expr     { $$ = new XBool2( $1, '&', $3 ); }
  269.         |   lxNil               { $$ = new XImmediate( new CNil ); }
  270.         |   lxTrue              { $$ = new XImmediate( new CBool( 1 )); }
  271.         |   lxFalse             { $$ = new XImmediate( new CBool( 0 )); }
  272.  
  273.         |   expr '<'  expr      { $$ = new XComparison( $1, '<', $3 ); }
  274.         |   expr '>'  expr      { $$ = new XComparison( $1, '>', $3 ); }
  275.         |   expr '='  expr      { $$ = new XComparison( $1, '=', $3 ); }
  276.         |   expr lxNe expr      { $$ = new XComparison( $1, '~', $3 ); }
  277.         |   expr lxGe expr      { $$ = new XComparison( $1, '}', $3 ); }
  278.         |   expr lxLe expr      { $$ = new XComparison( $1, '{', $3 ); }
  279.         |   assign              { $$ = $1; }
  280.         ;
  281. boolean :   expr                { $$ = $1; }
  282.         ;
  283. term    :   '('expr')'  { $$ = $2; }
  284.         |   lxInt       { $$ = new XImmediate( new CLong  ( $1 )); }
  285.         |   lxReal      { $$ = new XImmediate( new CDouble( $1 )); }
  286.         |   lxString    { $$ = new XImmediate( new CString( $1 )); }
  287.         |   lxEndl      { $$ = new XEndl; }
  288.         |   callf       { $$ = $1; }
  289.         |   array       { $$ = $1; }
  290.         |   var         { $$ = $1; }
  291.         |   const       { $$ = $1; }
  292.         |   lxUser      { $$ = UserSym( $1 ); }
  293.         ;
  294. var     :   yyVar       { $$ = new XVariable( $1 );}
  295.         |   var idx     { ($$ = new XVariable( $1, &$1->v ))->
  296.                             Add( $1 )->Add( $2 ); }
  297.         ;
  298. const   :   yyConst     { $$ = new XVariable( $1 );}
  299.         |   const idx   { ($$ = new XVariable( $1, &$1->v ))->
  300.                             Add( $1 )->Add( $2 ); }
  301.         ;
  302. idx     :   '['expr']'  { $$ = $2; }
  303.         |   '.' { HideVars = 1; } lxName
  304.             { $$ = new XImmediate( new CString( $3 )); HideVars = 0; }
  305.         ;
  306. array   :   '{' { Sets.Push( new XSet ); } elems '}'
  307.             { $$ = (XSet*)Sets.Last(); Sets.Pop(); }
  308.         ;
  309. elems   :
  310.         |   elem            {}
  311.         |   elems','elem    {}
  312.         ;
  313. elem    :   expr    { XSet* s = (XSet*)Sets.Last(); s->Add( $1 ); }
  314.         ;
  315. fname   :   yyFunc      { $$ = $1; }
  316.         |   yyProc      { $$ = $1; }
  317.         ;
  318. func    :   extern '('
  319.             {
  320.                 HideVars = 1;
  321.                 FuncTmp = $$ = $1;
  322.                 Blocks.Push( FuncTmp );
  323.                 if( $1->Defined())
  324.                 {
  325.                     yyerror("symbol is already defined");
  326.                     yyerrok;
  327.                 }
  328.             }
  329.             locals
  330.             {
  331.                 HideVars=0;
  332.                 XBlock *x = new XBlock;
  333.                 FuncTmp->Add( x );
  334.                 Blocks.Push( x );
  335.             }
  336.             ')' stats lxEnd ';'
  337.             {
  338.                 $$ = FuncTmp;
  339.                 Blocks.Pop();
  340.                 Blocks.Pop();
  341.             }
  342.         ;
  343. declf   :   lxFunc  { $$ = FuncTmp = new XFunction( 0 ); }
  344.         |   lxProc  { $$ = FuncTmp = new XFunction( 1 ); }
  345.         ;
  346. locals  :
  347.         |   local           {}
  348.         |   locals','local  {}
  349.         ;
  350. local   :   lxName  { FuncTmp->AddLocal( $1, yyVar ); }
  351.         ;
  352. callp   :   yyProc { Calls.Push( new XCall( $1 )); }'(' args ')'
  353.                     { $$ = (XCall*)Calls.Last(); Calls.Pop(); }
  354.         ;
  355. callf   :   yyFunc { Calls.Push( new XCall( $1 )); }'(' args ')'
  356.                     { $$ = (XCall*)Calls.Last(); Calls.Pop(); }
  357.         |   '&''('expr')' { XCall *c = new XDynamic(
  358.                 $3, &Global->funcs ); Calls.Push( c ); }'(' args ')'
  359.                 { $$ = (XCall*)Calls.Last(); Calls.Pop(); }
  360.         ;
  361. args    :
  362.         |   arg         {}
  363.         |   args','arg  {}
  364.         ;
  365. arg     :   expr     { ((XCall*)Calls.Last())->Add( $1 ); }
  366.         |   '*'var   { ((XCall*)Calls.Last())->Add( $2 ); $2->ref = 1; }
  367.         ;
  368. extern  :   declf lxName
  369.             {
  370.                 $1->SetName( $2 );
  371.                 ($$ = $1)->father = Global;
  372.                 Global->funcs.Add( new LexFunc( $$->name, $$,
  373.                     $$->isProc ? yyProc : yyFunc ));
  374.             }
  375.         |   declf fname
  376.             {
  377.                 if( $1->isProc!=$2->isProc )
  378.                 {
  379.                     yyerror( "conflict with ",$2->name );
  380.                     yyerrok;
  381.                 }
  382.                 delete $1;
  383.                 $$ = $2;
  384.             }
  385.         ;
  386. %%
  387. char *CalcPlus::pyylval(){ return (char*)&yylval; }
  388. Token CalcPlus::__name()
  389. {
  390.     Token t = YLex::__name();
  391.     if( HideVars || t!=lxName )
  392.         return t;
  393.     LexObj* p;
  394.     for( p = Blocks.LastInList; p; p = p->PrevInList )
  395.         LOOKUP(((XBlock*)(((LexRef*)p)->Obj()))->vars, LexVar );
  396.     LOOKUP( Global->funcs, LexFunc );
  397.     LOOKUP( XUserFunction::funcs, LexFunc );
  398.     for( p = Blocks.LastInList; p; p = p->PrevInList )
  399.         LOOKUP(((XBlock*)(((LexRef*)p)->Obj()))->structs, LexStruct );
  400.     return lxName;
  401. }
  402.  
  403. Var* CalcPlus::AddVar( const char* s )
  404. {
  405.     LexVar* o = (LexVar*)(XSEQ->vars( s ));
  406.     if( o )
  407.         return o->data;
  408.     Var *v = new Var( s, DeclType == declConst );
  409.     XSEQ->vars.Add( new LexVar( s, v,
  410.         v->isConst ? yyConst : yyVar ));
  411.     if( StructTmp )
  412.     {
  413.         CArray *a = new CArray( *StructTmp );
  414.         a->structure = new CArray( *a );
  415.         delete v->v;
  416.         v->v = a;
  417.     }
  418.     return v;
  419. }
  420.  
  421. Expression* CalcPlus::UserSym( Expression*, Expression* )
  422. {
  423.     yyerror("user symbols beginning with '@' are not supported");
  424.     return new XImmediate( new CNil );
  425. }
  426.  
  427. CalcPlus::CalcPlus( const char* s ) :
  428.     HideVars( 0 ), YLex( s )
  429. {
  430.     Blocks.Push( Global = new XBlock );
  431.     UserLib();
  432. }
  433.  
  434. CalcPlus::~CalcPlus()
  435. {
  436.     delete Global;
  437. }
  438.  
  439. void CalcPlus::print( ostream& o ) const
  440. {
  441.     XBlock& X = *Global;
  442.     if( X.n )
  443.         o << X << ';' << endl << endl;
  444.     for( LexObj *p = X.funcs.FirstInList;
  445.         p; p = p->NextInList )
  446.             o << (*((LexFunc*)p)->data) << ';' << endl << endl;
  447. }
  448.  
  449. CalcPlus::Err()
  450. {
  451.     if( !errors->isEmpty())
  452.     {
  453.         Errors( cout );
  454.         return 1;
  455.     }
  456.     const Expression* e = Global->LocateError();
  457.     if( e )
  458.     {
  459.         cout << "Error in expression: " << *e << endl;
  460.         return 1;
  461.     }
  462.     return 0;
  463. }
  464.  
  465. CalcPlus::Compile()
  466. {
  467.     yyparse();
  468.     if( Blocks.NumObj != 1 )
  469.         yyerror();
  470.     if( Expression::Debug )
  471.         cout << *this << endl;
  472.     return Err();
  473. }
  474.  
  475. CalcPlus::Link()
  476. {
  477.     XBlock& x = *Global;
  478.     if( StartSym())
  479.     {
  480.         LexObj* o = x.funcs( StartSym() );
  481.         if( !o )
  482.         {
  483.             cerr << "Start symbol is not defined: "
  484.                  << StartSym() << endl;
  485.             return 1;
  486.         }
  487.         XFunction* f = ((LexFunc*)o)->data;
  488.         x.Add( new XCall( f ));
  489.     }
  490.     x.Recursion( &Expression::Link );
  491.     LexObj* p;
  492.     for( p = x.funcs.FirstInList; p; p = p->NextInList )
  493.         ((LexFunc*)p)->data->Recursion( &Expression::Link );
  494.     for( p = x.funcs.FirstInList; p; p = p->NextInList )
  495.     {
  496.         XFunction *f = ((LexFunc*)p)->data;
  497.         if( f->flags & Expression::exLink )
  498.             yyerror( "undefined symbol ", f->name );
  499.         if( f->flags & Expression::exArgs )
  500.             yyerror( "wrong number of arguments - ", f->name );
  501.         if( f->flags & Expression::exRet )
  502.             yyerror( "wrong usage of RETURN - ", f->name );
  503.     }
  504.     return Err();
  505. }
  506.  
  507. CType* CalcPlus::Call( const char* f, int argc, ... )
  508. {
  509.     LexObj* o = Global->funcs( f );
  510.     if( !o )
  511.     {
  512.         cerr << "undefined symbol " << f << endl;
  513.         return 0;
  514.     }
  515.     XCall c(((LexFunc*)o)->data );
  516.     va_list l;
  517.     va_start( l, argc );
  518.     for( int i = 0; i < argc; i++ )
  519.     {
  520.         CType *t = va_arg( l, CType* );
  521.         c.Add( new XImmediate( t->copy() ));
  522.     }
  523.     va_end( l );
  524.     c.Link();
  525.     const mask =
  526.         Expression::exLink |
  527.         Expression::exArgs |
  528.         Expression::exRet
  529.         ;
  530.     if( c.flags & mask )
  531.     {
  532.         const Expression *e = c.LocateError( mask );
  533.         if( e )
  534.             cerr << "error in expression " << *e << endl;
  535.         cerr << "linker error, symbol " << f << endl;
  536.         return 0;
  537.     }
  538.     c.father = Global;
  539.     c.Calculate();
  540.     if( c.flags )
  541.     {
  542.         const Expression *e = c.LocateError( Expression::exError );
  543.         if( e )
  544.             cerr << "error in expression " << *e << endl;
  545.         cerr << "interpreter errror" << endl;
  546.         return 0;
  547.     }
  548.     return c.Func->v;
  549. }
  550.  
  551. CalcPlus::Exec()
  552. {
  553.     Global->Calculate();
  554.     return Err();
  555. }
  556.  
  557. CalcPlus::Run()
  558. {
  559.     return Compile() || Link() || Exec();
  560. }
  561.  
  562.