/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

%{
#include <stdlib.h>
#include <stdio.h>
extern void newline(int);
%}

%start script

%token IF
%token AND
%token NOT
%token OR
%token THEN
%token ELSE
%token END
%token RETURN
%token DO
%token FUNCTION
%token ON
%token GLOBAL
%token VECTOR
%token WHILE
%token INCLUDE
%token EXTERN
%token GE
%token LE
%token NE
%token FOR
%token TO
%token BY
%token NIL
%token OBJECT
%token IMPORT
%token EXPORT
%token INLINE
%token ENDINLINE

%token CASE
%token OTHERWISE
%token OF

%token IN

%token REPEAT
%token UNTIL
%token LOOP
%token WHEN
%token TELL
%token TASK

%token WORD
%token STRING
%token NUMBER
%token DATE
%token TIME

%token ARROW


%%

script  : block { theend(); } 
        ;

block   : lines
        | empty
        ;

lines   : line       
        | lines line
        ;

line    : statement  { newline(0); }
        | function 
        | control   
        | declare    { newline(0); }
        | extern     { newline(1); }
        | import     { newline(1); }
        | export     { newline(1); }
        | include    { newline(1); }
        | ';'
        ;


name    : WORD;

declare : GLOBAL name
        | GLOBAL name '=' expression
        ;

extern  : extern_name extern_param_declare
        | extern_name extern_param_declare  STRING
        | extern_name extern_param_declare  STRING inline
        ;

extern_name : EXTERN fname 
            ;

import      : IMPORT name
            ;

export      : EXPORT name
            ;

include     : INCLUDE STRING
            | INCLUDE name
            ;

inline      : INLINE  ENDINLINE
            ;

/*======================================================================*/

function : beginfunction block  endfunction
         ;

beginfunction : functionheader  param_declare super_declare
			;

param_declare : empty                    { newline(0); tabs(1); } 
              | rbra rket                { newline(1); tabs(1); } 
              | rbra param_list rket     { newline(1); tabs(1); } 
              ;

super_declare   : empty
				| ':' super_list
				;

super_list : super
			| super_list ',' super
			;

super : function_call 
	;

extern_param_declare : empty
                     | rbra rket
                     | rbra param_list rket
                     ;

functionheader : FUNCTION fname  
               | ON       fname 
			   | OBJECT   fname
               ;

param_list     : param                      
               | param_list ',' param       
               ;

param          : name                       
               | name ':' name              
               ;

endfunction    : END { tabs(-1); } fname            { newline(1); }
             ;

fname          : name
			   | operator
			   ;


/*======================================================================*/

statement   : assignement  
            | function_call
            | return  
            | name   
            ;

return      : RETURN                        
            | RETURN expression             

/*======================================================================*/

assignement : name '=' expression       
            | name sbra parameters sket '=' expression       
            | name '.' name   '='  expression
            | name '.' NUMBER '='  expression
            ;

/*======================================================================*/

control     : if   
            | while 
            | for   
            | repeat
            | case   
            | loop   
            | when   
            | tell   
            ;

/*======================================================================*/

loop        : LOOP name IN expression      { newline(0); tabs(1);}
                block 
              END { tabs(-1); } LOOP       { newline(1);}
            ;


/*======================================================================*/
tell       : TELL expression               { newline(0); tabs(1);}
                  block
             END { tabs(-1); } TELL        { newline(1);}
           ;

/*======================================================================*/

when        : WHEN                         { newline(1); tabs(1);} 
                selections
              END {tabs(-1); } WHEN        { newline(1);} 

selections  : selection
            | selections selection
            ;

selection   : expression ':'                 { newline(1); tabs(1);}
                block END                    { newline(1); tabs(-1);}

/*======================================================================*/

case        : CASE expression OF          { newline(1); tabs(1);} 
                choices
                otherwise
              END { tabs(-1); } CASE      { newline(1);} 
            ;

choices     : choice 
            | choices choice
            ;

choice      :   parameters ':'            { newline(1); tabs(1);} 
                         block END        { newline(1); tabs(-1);} 
            ;

otherwise   :   empty                    
            |   OTHERWISE  ':'            { newline(1); tabs(1);}
                         block END        { newline(1); tabs(-1);}
            ;
            

/*======================================================================*/
repeat      : REPEAT                           { newline(1); tabs(1);}     
                 block
              UNTIL { tabs(-1); } expression   { newline(0);}
            ;

/*======================================================================*/

for         :  FOR name '=' expression TO expression by 
					DO  { newline(1);tabs(1);}
                      block
               END FOR  {tabs(-1); newline(1); }
            ;
            
by          : empty         
            | BY expression 
            ;

/*======================================================================*/

while       : WHILE expression DO          { newline(1); tabs(1); } 
                 block
              END { tabs(-1); } WHILE      { newline(1);} 
            ;

/*======================================================================*/

if          : IF expression THEN           { newline(1); tabs(1); }
                 block 
              closeif                      
            ;

closeif     : END  { tabs(-1);} IF           { newline(1);}
            | else { newline(0); tabs(1);}  block closeif 
            | else IF expression THEN { newline(1); tabs(1); } block closeif                
            ;

else        : ELSE { tabs(-1);}
/*======================================================================*/

rbra : '('  { bra(); }
     ;

rket : ')'  { ket(); }
     ;

sbra : '['  { bra(); }
     ;

sket : ']'  { ket(); }
     ;


definition : rbra attribute_list rket
           | rbra parameter ',' parameters rket
		   | rbra rket
           ;

                
function_call   : name rbra param_or_empty rket
                | name rbra attribute_list rket
                | definition
				| inline_object
                | atom sbra parameters sket
                | atom '.' name           
                | atom '.' NUMBER
				| name ARROW name rbra param_or_empty rket
				| name ARROW name rbra attribute_list rket
                ;

inline_object : name inline
			;

/*======================================================================*/


param_or_empty  : empty                         
                | parameters
                ;

parameters  : parameter                     
            | parameter ',' parameters      
            ;

parameter   : expression
            ;

attribute   : name ':' expression
            | STRING ':' expression
            ;

attribute_list : attribute                    
               | attribute ',' parameter      
               | attribute ',' attribute_list 
               | parameter ',' attribute_list 
               ;

vector_list : vector vector           
            | vector_list vector      
            ;

matrix      : vector_list               
            ;

vector      : '|' parameters '|'        
            ;

list        : sbra param_or_empty sket
            ;

number      : NUMBER                
            | '-' NUMBER            
            ;

atom        : name                  
            | STRING                
            | DATE TIME             
            | DATE                  
            | TIME                  
            | function_call
            | rbra expression rket
            | list
            | vector
            | matrix
            | NIL                   
            | '-' atom              
            ;

atom_or_number: atom
              | number
              ;


/* note: a^b^c -> a^(b^c) as in fortran */
power       : atom_or_number '^' power        
            | atom_or_number
            ;

factor      : factor '*' power      
            | factor '/' power      
            | power
            ;

term        : term '+' factor       
            | term '-' factor       
            | term '&' factor       
            | factor
            ;

condition   : condition '>' term         
            | condition '=' term         
            | condition '<' term         
            | condition  GE term         
            | condition  LE term         
            | condition  NE term         
            | condition  IN term         
            | condition  NOT IN term     
            | NOT condition              
            | term
            ;

operator    : '>'
			| '=' 
			| '<'
			| GE
			| LE 
			| NE
			| IN
			| NOT
			| '^'
			| '*'
			| '/'
			| '+'
			| '-'
			| '&'
			| AND
			| OR
			| '[' ']'
			;

conjonction : conjonction AND condition    
            | condition
            ;

disjonction : disjonction OR conjonction 
            | conjonction
            ;

expression  : disjonction
            ;

empty       :
            ;

%%
#include "beaul.c"

