//*******************************************************************************
//parser.h
//*******************************************************************************
//This file is part of the Orb compiler,
//Copyright (C) 2007 Adrian Fraga Fernandez
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//*******************************************************************************

/***********************************************************************/
/* Parser                                                              */
/***********************************************************************/

%{
#include "stdio.h"
#include "stdarg.h"
#include "error.h"
#include "ast.h"
#include "lexer.h"
#include "parser.h"
#define  YYSTYPE L_TOKEN

/***********************************************************************/
/* Variables globales                                                  */
/***********************************************************************/

static A_NODO 	*p_ast;	/* Arbol sintactico conteniendo el resultado */
			/* del parsing */

%}

/***********************************************************************/
/* Tipos de tokens                                                     */
/***********************************************************************/

%token  L_INDENT L_DEDENT L_NEWLINE
%token  L_ID L_LITERALENTERO L_LITERALREAL L_LITERALCADENA L_TRUE L_FALSE
%token 	L_ABSTRACT L_EXTERN L_SHARED L_VAR L_HIDDEN L_NATIVE
%token	L_BREAK L_CONTINUE L_DO L_ELSE L_FOR L_IF L_IN L_LET 
%token  L_RESEND L_RETURN L_STATIC L_THEN L_WHILE
%token  '(' ')' '.' ',' ';' '{' '}' '[' ']'
%token 	L_IS L_HAS
%token  '=' '+' '-' '*' '/' '%' 
%token  ':' L_UNION
%token	'>' '<' L_MAYORIGUAL L_MENORIGUAL L_IGUAL L_NOIGUAL L_IDENTICO L_NOIDENTICO
%token 	L_AND L_OR L_NOT
%token  '@'

/***********************************************************************/
/* Miscelanea                                                          */
/***********************************************************************/

%start	programa	// Simbolo raiz
%expect 1		// Se esperan dos conflicto desplaza/reduce (if/else con newlineCEROMAS)

%%

/***********************************************************************/
/* Definicion del lenguaje                                             */
/***********************************************************************/

programa		: cuerpoobjeto
				{
				e_copiaPosicion(&$$.posicion,$1.nodo==NULL?l_posicion():&$1.posicion);
				p_ast=$$.nodo=a_programa($1.nodo,&$$.posicion);
				}
		
/******************* Objetos *******************************************/

objeto			: padres cuerpo 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$2.posicion);
				$$.nodo=a_objeto(NULL,NULL,$1.nodo,$2.nodo,&$$.posicion);
				}
			| identificador L_UNION padres cuerpo 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$4.posicion);
				$$.nodo=a_objeto(NULL,$1.nodo,$3.nodo,$4.nodo,&$$.posicion);
				}
			| modobjeto objeto 
				{
				A_NODOOBJETO *temp;
				
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$2.posicion);	
				temp=(A_NODOOBJETO*)$2.nodo;
				temp->h1=a_nodo2(A_MODOBJETOLISTA,$1.nodo,temp->h1,&$1.posicion);
				$$.nodo=$2.nodo;
				temp=(A_NODOOBJETO*)$$.nodo;
				e_copiaPosicion(&temp->posicion,&$$.posicion);
				}

padres			: identificador comaidentificadorCEROMAS 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,$2.nodo==NULL?&$1.posicion:&$2.posicion);
				$$.nodo=a_nodo2(A_IDLISTA,$1.nodo,$2.nodo,&$$.posicion);
				}

comaidentificadorCEROMAS: /* epsilon */
				{
				$$.nodo=NULL;
				}
			| ',' identificador comaidentificadorCEROMAS 
				{		
				e_unionPosiciones(&$$.posicion,&$1.posicion,$3.nodo==NULL?&$2.posicion:&$3.posicion);
				$$.nodo=a_nodo2(A_IDLISTA,$2.nodo,$3.nodo,&$$.posicion);
				}


cuerpo			: '{' L_NEWLINE L_INDENT cuerpoobjeto L_DEDENT L_NEWLINE '}' 
				{								e_unionPosiciones(&$$.posicion,&$1.posicion,&$7.posicion);
				$$.nodo=$4.nodo;
				}
			| '{' L_NEWLINE '}'
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=NULL;
				}
			| '{' declobjeto '}'
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=$2.nodo;
				}
			| '{' '}'
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$2.posicion);
				$$.nodo=NULL;
				}
			|'{' L_NEWLINE L_INDENT cuerpoobjeto L_DEDENT L_NEWLINE declobjeto
				{							
				e_copiaPosicion(&$$.posicion,&$7.posicion);
				$$.nodo=a_nodoerror(&$$.posicion);
				e_error(&$$.posicion,"Error de sangrado (sangrado no consistente entre miembros del mismo objeto)");
				}			
			|'{' L_NEWLINE objeto 
				{								e_copiaPosicion(&$$.posicion,&$3.posicion);
				$$.nodo=a_nodoerror(&$$.posicion);
				e_error(&$$.posicion,"Error de sangrado (sangrado de miembro al mismo nivel que declaracion de objeto)");
				}		
			|'{' L_NEWLINE miembro 
				{								e_copiaPosicion(&$$.posicion,&$3.posicion);
				$$.nodo=a_nodoerror(&$$.posicion);
				e_error(&$$.posicion,"Error de sangrado (sangrado de miembro al mismo nivel que declaracion de objeto)");
				}			
				
cuerpoobjeto		: /*epsilon*/
				{
				$$.nodo=NULL;
				}
			| declobjeto cuerpoobjetoCEROMAS
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,$2.nodo==NULL?&$1.posicion:&$2.posicion);
				$$.nodo=a_nodo2(A_CUERPOOBJETOLISTA,$1.nodo,$2.nodo,&$$.posicion);
				}
				
cuerpoobjetoCEROMAS	: /*epsilon*/
				{
				$$.nodo=NULL;
				}
			| L_NEWLINE declobjeto cuerpoobjetoCEROMAS 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,$3.nodo==NULL?&$2.posicion:&$3.posicion);
				$$.nodo=a_nodo2(A_CUERPOOBJETOLISTA,$2.nodo,$3.nodo,&$$.posicion);
				}

declobjeto		: objeto 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| miembro
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| L_INDENT declobjeto L_NEWLINE
				{
				e_copiaPosicion(&$$.posicion,&$2.posicion);
				$$.nodo=a_nodoerror(&$$.posicion);
				e_error(&$$.posicion,"Error de sangrado (sangrado no consistente entre miembros del mismo objeto)");
				}
			| L_INDENT declobjeto L_DEDENT 
				{
				e_copiaPosicion(&$$.posicion,&$2.posicion);
				$$.nodo=a_nodoerror(&$$.posicion);
				e_error(&$$.posicion,"Error de sangrado (sangrado no consistente entre miembros del mismo objeto)");
				}
			| L_INDENT 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodoerror(&$$.posicion);
				e_error(&$$.posicion,"Error de sangrado");
				}
			| error 
				{
				A_NODO0 *temp;
				$$.nodo=a_nodo0(A_ERROR,l_posicion());
				temp=(A_NODO0*)$$.nodo;
				e_copiaPosicion(&$$.posicion,&temp->posicion);
				}
			
modobjeto		: L_ABSTRACT 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodo0(A_ABSTRACT,&$$.posicion);
				}
			| L_NATIVE
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodo0(A_NATIVE,&$$.posicion);
				}				
			| L_HIDDEN
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodo0(A_HIDDEN,&$$.posicion);
				}
			
/******************* Miembros ******************************************/

miembro			: identificador ':' cuerpomiembro
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_miembro(NULL,$1.nodo,NULL,$3.nodo,&$$.posicion);
				}
			| identificador argumentos ':' cuerpomiembro 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$4.posicion);
				$$.nodo=a_miembro(NULL,$1.nodo,$2.nodo,$4.nodo,&$$.posicion);
				}
			| modmiembro miembro
				{
				A_NODOMIEMBRO *temp;
				
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$2.posicion);
				temp=(A_NODOMIEMBRO*)$2.nodo;
				temp->h1=a_nodo2(A_MODMIEMBROLISTA,$1.nodo,temp->h1,&$$.posicion);
				$$.nodo=$2.nodo;
				e_copiaPosicion(&temp->posicion,&$$.posicion);
				}
			
cuerpomiembro		: L_ABSTRACT
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodo0(A_ABSTRACT,&$$.posicion);
				}
			| L_NATIVE
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodo0(A_NATIVE,&$$.posicion);
				}
			| L_EXTERN literalCadena literalCadena literalCadena
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$4.posicion);
				$$.nodo=a_nodo3(A_MIEMBROEXTERNO,$2.nodo,$3.nodo,$4.nodo,&$$.posicion);
				}
			| expresion
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| error
				{
				A_NODO0 *temp;
				
				$$.nodo=a_nodo0(A_ERROR,l_posicion());
				temp=(A_NODO0*)$$.nodo;
				e_copiaPosicion(&$$.posicion,&temp->posicion);
				}
						
modmiembro		: L_SHARED
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodo0(A_SHARED,&$$.posicion);
				}
			| L_VAR 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodo0(A_VAR,&$$.posicion);
				}
			
/******************* Argumentos y parametros **************************/


argumentos		: '(' ')' 
				{
				$$.nodo=NULL;
				}
			| '(' identificador comaargumentoCEROMAS ')' 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$4.posicion);
				$$.nodo=a_nodo2(A_ARGUMENTOSLISTA,$2.nodo,$3.nodo,&$$.posicion);
				}

comaargumentoCEROMAS    : /* epsilon */
				{
				$$.nodo=NULL;
				}
			| ',' identificador comaargumentoCEROMAS 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,$3.nodo==NULL?&$2.posicion:&$3.posicion);
				$$.nodo=a_nodo2(A_ARGUMENTOSLISTA,$2.nodo,$3.nodo,&$$.posicion);
				}


parametros		: '(' ')' 
				{
				$$.nodo=NULL;
				}
			| '(' expresion comaexpresionCEROMAS ')' 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$4.posicion);
				$$.nodo=a_nodo2(A_PARAMETROSLISTA,$2.nodo,$3.nodo,&$$.posicion);
				}

comaexpresionCEROMAS	: /* vacio */
				{
				$$.nodo=NULL;
				}
			| ',' expresion comaexpresionCEROMAS 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,$3.nodo==NULL?&$2.posicion:&$3.posicion);
				$$.nodo=a_nodo2(A_PARAMETROSLISTA,$2.nodo,$3.nodo,&$$.posicion);
				}

/******************* Expresiones ***************************************/
			
expresion		: expresion15
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| expresion ';' expresion15
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_SECUENCIA,$1.nodo,$3.nodo,&$$.posicion);
				}

newlineCEROUNO		: /* epsilon */
			| L_NEWLINE
				
expresion15		: L_IF expresion newlineCEROUNO L_THEN expresion15
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$5.posicion);
				$$.nodo=a_nodo3(A_IF,$2.nodo,$5.nodo,NULL,&$$.posicion);
				}
			| L_IF expresion newlineCEROUNO L_THEN expresion15 L_ELSE expresion15
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$7.posicion);
				$$.nodo=a_nodo3(A_IF,$2.nodo,$5.nodo,$7.nodo,&$$.posicion);
				}
			| L_ELSE expresion15
				{
				/* emparejamiento durante análisis semántico */
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$2.posicion);
				$$.nodo=a_nodo3(A_IF,NULL,NULL,$2.nodo,&$$.posicion);
				}
			| L_WHILE expresion newlineCEROUNO L_DO expresion15
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$5.posicion);
				$$.nodo=a_nodo2(A_WHILE,$2.nodo,$5.nodo,&$$.posicion);
				}
			| L_DO expresion newlineCEROUNO L_WHILE expresion15
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$5.posicion);
				$$.nodo=a_nodo2(A_DOWHILE,$2.nodo,$5.nodo,&$$.posicion);
				}
			| L_FOR expresion ',' expresion ',' expresion newlineCEROUNO L_DO expresion15
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$9.posicion);
				$$.nodo=a_nodo4(A_FOR,$2.nodo,$4.nodo,$6.nodo,$9.nodo,&$$.posicion);
				}
			| L_BREAK
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodo0(A_BREAK,&$$.posicion);
				}
			| L_CONTINUE
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodo0(A_CONTINUE,&$$.posicion);
				}
			| L_RETURN expresion15
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$2.posicion);
				$$.nodo=a_nodo1(A_RETURN,$2.nodo,&$$.posicion);
				}
			| L_STATIC expresion15
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$2.posicion);
				$$.nodo=a_nodo1(A_STATIC,$2.nodo,&$$.posicion);
				}
			| L_RESEND
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodo3(A_RESEND,NULL,NULL,NULL,&$$.posicion);
				}
			| L_RESEND parametros 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$2.posicion);
				$$.nodo=a_nodo3(A_RESEND,NULL,NULL,$2.nodo,&$$.posicion);
				}
			| L_RESEND '@' identificador
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo3(A_RESEND,$3.nodo,NULL,NULL,&$$.posicion);
				}
			| L_RESEND '@' identificador parametros
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$4.posicion);
				$$.nodo=a_nodo3(A_RESEND,$3.nodo,NULL,$4.nodo,&$$.posicion);
				}
			| L_RESEND '@' identificador '@' identificador
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$5.posicion);
				$$.nodo=a_nodo3(A_RESEND,$3.nodo,$5.nodo,NULL,&$$.posicion);
				}
			| L_RESEND '@' identificador '@' identificador parametros
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$6.posicion);
				$$.nodo=a_nodo3(A_RESEND,$3.nodo,$5.nodo,$6.nodo,&$$.posicion);
				}
			| L_LET variables newlineCEROUNO L_IN expresion15
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$5.posicion);
				$$.nodo=a_let($2.nodo,$5.nodo,&$$.posicion);
				}
			| expresion20
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			
variable		: identificador
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodo3(A_DECLARACIONLISTA,$1.nodo,NULL,NULL,&$$.posicion);
				}
			| identificador '=' expresion
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo3(A_DECLARACIONLISTA,$1.nodo,$3.nodo,NULL,&$$.posicion);
				}
			
variables		: variable
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| variable ',' variables
				{
				A_NODO3 *temp;
								
				$$.nodo=$1.nodo;
				temp=(A_NODO3*)$$.nodo;
				temp->h3=$3.nodo;
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				}

expresion20		: expresion25
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}				
			| expresion25 '=' expresion20
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_ASIGNACION,$1.nodo,$3.nodo,&$$.posicion);
				}


expresion25		: expresion30 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| expresion25 L_OR expresion30 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_OR,$1.nodo,$3.nodo,&$$.posicion);
				}

expresion30		: expresion40 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| expresion30 L_AND expresion40 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_AND,$1.nodo,$3.nodo,&$$.posicion);
				}

expresion40		: expresion60 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| expresion60 L_IGUAL expresion60
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_IGUAL,$1.nodo,$3.nodo,&$$.posicion);
				}
			| expresion60 L_NOIGUAL expresion60
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_NOIGUAL,$1.nodo,$3.nodo,&$$.posicion);
				}
			| expresion60 L_IDENTICO expresion60
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_IDENTICO,$1.nodo,$3.nodo,&$$.posicion);
				}
			| expresion60 L_NOIDENTICO expresion60
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_NOIDENTICO,$1.nodo,$3.nodo,&$$.posicion);
				}
			| expresion60 '>' expresion60
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_MAYOR,$1.nodo,$3.nodo,&$$.posicion);
				}
			| expresion60 '<' expresion60
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_MENOR,$1.nodo,$3.nodo,&$$.posicion);
				}
			| expresion60 L_MENORIGUAL expresion60
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_MENORIGUAL,$1.nodo,$3.nodo,&$$.posicion);
				}
			| expresion60 L_MAYORIGUAL expresion60
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_MAYORIGUAL,$1.nodo,$3.nodo,&$$.posicion);
				}

expresion60		: expresion70 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| expresion60 L_UNION expresion70 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_UNION,$1.nodo,$3.nodo,&$$.posicion);
				}

expresion70		: expresion90 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| expresion70 ':' expresion90 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_CONCATENACION,$1.nodo,$3.nodo,&$$.posicion);
				}
			
expresion90		: expresion100 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| expresion90 '+' expresion100 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_SUMA,$1.nodo,$3.nodo,&$$.posicion);
				}
			| expresion90 '-' expresion100 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_RESTA,$1.nodo,$3.nodo,&$$.posicion);
				}

expresion100		: expresion110 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| expresion100 '*' expresion110 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_MULTIPLICACION,$1.nodo,$3.nodo,&$$.posicion);
				}
			| expresion100 '/' expresion110 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_DIVISION,$1.nodo,$3.nodo,&$$.posicion);
				}
			| expresion100 '%' expresion110 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_MODULO,$1.nodo,$3.nodo,&$$.posicion);
				}
			
expresion110		: expresion120 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| '+' expresion110 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$2.posicion);
				$$.nodo=a_nodo1(A_MAS,$2.nodo,&$$.posicion);
				}
			| '-' expresion110 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$2.posicion);
				$$.nodo=a_nodo1(A_MENOS,$2.nodo,&$$.posicion);
				}
			| L_NOT expresion110 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$2.posicion);
				$$.nodo=a_nodo1(A_NOT,$2.nodo,&$$.posicion);
				}

expresion120		: expresion130 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| expresion130 L_IS identificador 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_IS,$1.nodo,$3.nodo,&$$.posicion);
				}
			| expresion130 L_IS L_NOT identificador 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$4.posicion);
				$$.nodo=a_nodo2(A_ISNOT,$1.nodo,$4.nodo,&$$.posicion);
				}
			| expresion130 L_HAS identificador 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo2(A_HAS,$1.nodo,$3.nodo,&$$.posicion);
				}
			| expresion130 L_HAS L_NOT identificador 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$4.posicion);
				$$.nodo=a_nodo2(A_HASNOT,$1.nodo,$4.nodo,&$$.posicion);
				}

expresion130		: expresion140 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| expresion130 '[' expresion ']'
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$4.posicion);
				$$.nodo=a_nodo2(A_ACCESOARRAY,$1.nodo,$3.nodo,&$$.posicion);
				} 
			| expresion130 '.' identificador 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=a_nodo3(A_ACCESOMIEMBRO,$1.nodo,$3.nodo,NULL,&$$.posicion);
				}
			| expresion130 '.' identificador parametros 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$4.posicion);
				$$.nodo=a_nodo3(A_ACCESOMIEMBRO,$1.nodo,$3.nodo,$4.nodo,&$$.posicion);
				}

expresion140		: '(' expresion ')' 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$3.posicion);
				$$.nodo=$2.nodo;
				}
			| identificador 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodo2(A_IDATOMICO,$1.nodo,NULL,&$$.posicion);
				}
			| identificador parametros 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$2.posicion);
				$$.nodo=a_nodo2(A_IDATOMICO,$1.nodo,$2.nodo,&$$.posicion);
				}			
			| literalEntero
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| literalReal 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| literalCadena
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| literalsecuencia 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=$1.nodo;
				}
			| L_TRUE
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodo0(A_LITERALTRUE,&$$.posicion);
				}
			| L_FALSE
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_nodo0(A_LITERALFALSE,&$$.posicion);
				}
			| L_NEWLINE L_INDENT expresion expresionCEROMAS L_DEDENT
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$5.posicion);
				
				if ($4.nodo==NULL) $$.nodo=$3.nodo;
				else $$.nodo=a_nodobloque($3.nodo,$4.nodo,&$$.posicion);
					
				}
			| L_DEDENT L_NEWLINE expresion L_NEWLINE L_INDENT
				{
				e_error(&$3.posicion,"Error de sangrado");
				$$.nodo=a_nodoerror(&$$.posicion);
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$5.posicion);
				}
					
expresionCEROMAS	: /* epsilon */
				{
				$$.nodo=NULL
				}
			| L_NEWLINE expresion expresionCEROMAS
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,$3.nodo==NULL?&$2.posicion:&$3.posicion);
				
				if ($3.nodo==NULL) $$.nodo=$2.nodo;
				else $$.nodo=a_nodobloque($2.nodo,$3.nodo,&$$.posicion);
				}
			| L_NEWLINE L_INDENT expresion expresionCEROMAS L_DEDENT expresionCEROMAS
				{
				e_error(&$2.posicion,"Error de sangrado");
				e_unionPosiciones(&$$.posicion,&$1.posicion,$6.nodo==NULL?&$5.posicion:&$6.posicion);
				$$.nodo=a_nodoerror(&$$.posicion);
				}

literalsecuencia	: '[' ']'
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$2.posicion);
				
				$$.nodo=a_nodo1(A_LITERALSECUENCIA,NULL,&$$.posicion);
				}
			| '[' expresion literalsecuenciaCEROMAS ']' 
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,&$4.posicion);
				
				$$.nodo=a_nodo1(A_LITERALSECUENCIA,
					a_nodo2(A_LITERALSECUENCIALISTA,$2.nodo,$3.nodo,&$$.posicion),&$$.posicion);
				}

literalsecuenciaCEROMAS	: /* vacio */
				{
				$$.nodo=NULL;
				}
			| ',' expresion literalsecuenciaCEROMAS
				{
				e_unionPosiciones(&$$.posicion,&$1.posicion,
					$3.nodo==NULL?&$2.posicion:&$3.posicion);
				
				$$.nodo=a_nodo2(A_LITERALSECUENCIALISTA,$2.nodo,$3.nodo,&$$.posicion);
				}

literalEntero		: L_LITERALENTERO
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				$$.nodo=a_literalEntero($1.i,&$$.posicion);
				}
				
literalReal		: L_LITERALREAL
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				
				$$.nodo=a_literalReal($1.f,&$$.posicion);
				}
				
literalCadena		: L_LITERALCADENA
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);
				
				$$.nodo=a_literalCadena($1.s,&$$.posicion);
				}
				
identificador		: L_ID 
				{
				e_copiaPosicion(&$$.posicion,&$1.posicion);

				$$.nodo=a_id($1.id,&$$.posicion);
				}

%%

/***********************************************************************/
/* Errores de parsing, sintaxis e internos de Yacc                     */
/***********************************************************************/

int  yyerror(char *msg){
	if (!strcmp(msg,"parse error")){
		if (l_texto()==NULL)
			e_error(l_posicion(),"error de parsing antes de fin de archivo");
		else
			e_error(l_posicion(),"error de parsing antes de '%s'",l_texto());
	}
	else if (!strcmp(msg,"syntax error")){
		if (l_texto()==NULL)
			e_error(l_posicion(),"error de sintaxis antes de fin de archivo");
		else
			e_error(l_posicion(),"error de sintaxis antes de '%s'",l_texto());
	}
	else{
		e_fatal(l_posicion(),msg);
	}
	return 0;
}

/***********************************************************************/
/* Interfaz                          				       */
/***********************************************************************/

A_NODO *p_parse(char *fichero){
	l_init(fichero);
	yyparse();
	l_close();
	return p_ast;
}

