grammar uot;

and_expr
	:	comp_expr
		( CONJ comp_expr
		)*
	;
	
aslong_statement
	:	ASLONG
		PAREN_OPEN
		expression
		PAREN_CLOSE
		BEGIN
    		stmt_list
    		END
	;
	
assignment
	:	IDENTIFIER
		ASSIGN
		expression
	;

arg_list
	:	|
		expression
		(COMMA
		expression)*
	;
	
atom
	:	(PLUS | MINUS)*
		core_atom
	;
	
comp_expr
	:	simp_expression
		(comp_operator
       		simp_expression)*
	;
	
comp_operator
	:	IS_EQUAL
    	|  	NOT_EQUAL
	|	GREATER
	|	GEQ
	|	LESS
	|	LEQ
	;

constant
	:	INT
	|	DOUBLE
	| 	STRING
 	|	TRUE
	|	FALSE
	;

core_atom
    	: 	func_call_or_ident
	|	constant
   	|   	PAREN_OPEN expression PAREN_CLOSE
	;

data_type
	:	TYPE_INT
	|	TYPE_DOUBLE
	|	TYPE_BOOLEAN
	|	TYPE_CHAR
	;
	
expression 
	:	or_expr
	;
	
field_decl
	:	modifier*
		yield_type
		IDENTIFIER
		(ASSIGN
		expression)?
		SEMI
	;

formal
	:	data_type
		IDENTIFIER
	;
	
formal_list
	:	|
		formal
		(COMMA
		formal)*
	;
	
func_call_or_ident
	:	IDENTIFIER
		(PAREN_OPEN
		arg_list
		PAREN_CLOSE)?
	;

func_decl
	:	modifier*
		yield_type
		IDENTIFIER
		PAREN_OPEN
		formal_list
		PAREN_CLOSE
		BEGIN
		stmt_list
		END
	;
	
member_decl
	:	field_decl
	|	func_decl
	;
	
modifier
	:	VISIBLE
	|	SHIELDED
	|	ONLYONE
	|	CONSTANT
	|	HIDDEN
	;

or_expr
	:	and_expr
        	( DISJ and_expr
	        )*
	;

prog
	:	using_stmt*
		prototype_decl*
		EOF
	;

prototype_body
	:	BEGIN
		member_decl*
		END
	;

prototype_decl
	:	modifier*
		PROTOTYPE
		IDENTIFIER
		prototype_body
	;
	
simp_expression
	:	term
		(PLUS term
		| MINUS term)*
	;
	
statement
	:  	(assignment
	|	yield_stmt
	|	var_decl
	|	expression)
		SEMI
	|   	when_statement
	|   	aslong_statement
	;

stmt_list
	:	statement*
	;

term	
	:	atom
		(MULT atom)*
	;
	
using_stmt
	:	USING
		IDENTIFIER
		(DIV
		IDENTIFIER)*
		(DIV
		MULT)?
		SEMI
	;
	
var_decl
	:	data_type
		IDENTIFIER
		(ASSIGN
		expression)?
	;
    
when_statement
	:	WHEN
	        PAREN_OPEN
	        expression
	        PAREN_CLOSE
	        BEGIN
	        stmt_list
	        (ORWHEN
	        PAREN_OPEN
	        expression
	        PAREN_CLOSE
	        stmt_list)*	        
	        (OTHERWISE
	        stmt_list)?
	        END
	;

yield_stmt
	:	YIELD
        	(expression)?
	;
	
yield_type
	:	data_type
	|	NOTHING
	;
			
PROTOTYPE
	:	'prototype'
	;
	
USING
	:	'using'
	;
	
VISIBLE
	:	'visible'
	;
	
CONSTANT
	:	'constant'
	;

HIDDEN
	:	'hidden'
	;

SHIELDED
	:	'shielded'
	;

ONLYONE
	:	'onlyone'
	;

NOTHING
	:	'nothing'
	;	
	
YIELD
	:	'yield'
	;

ASLONG
	:	'aslong'
	;

WHEN
   	:	'when'
	;
	
ORWHEN
	:	'orwhen'
	;

OTHERWISE
	:	'otherwise'
    	;


TRUE
	:	'true'
	;
	
FALSE
	:	'false'
	;
	
CONJ
	:	'and'
	;
	
DISJ
	:	'or'
	;

TYPE_INT
	:	'integer'
	;

TYPE_DOUBLE
	:	'double'
	;
	
TYPE_BOOLEAN
	:	'bool'
	;
	
TYPE_CHAR
	:	'char'
	;

COMMA
	:	','
	;

BEGIN
	:	'begin'
	;
	
END
	:	'end'
	;

PAREN_CLOSE
	:	')'
	;

PAREN_OPEN
	:	'('
	;

GREATER
	:	'greaterthan'
	;

GEQ
	:	'greaterorequal'
	;

LESS	
	:	'lessthan'
	;

LEQ
	:	'lessorequal'
	;
	
IS_EQUAL
	:	'is'
	;

NOT_EQUAL
	:	'isnot'
	;

IDENTIFIER
	:	A3LETTER
		A3LETTERORDIGIT*
	;

fragment
A3LETTERORDIGIT
	:	A3LETTER
	|	A3DIGIT
	;

WS      
	:       (' '|'\t'|'\f'|'\n'|'\r') {skip();}
	;
	

DIV	
	:	'/'
	;

DOT	
	:	'.'
	;

ASSIGN
	:	'<-'
	;

fragment
A3DIGIT
	:	'0'..'9'
	;

	
INT	
	:	'0'..'9'+
	;

DOUBLE
 	:	('0'..'9')+ '.' ('0'..'9')* EXPONENT?
	|	'.' ('0'..'9')+ EXPONENT?
	|	('0'..'9')+ EXPONENT
	;

fragment
EXPONENT
	:	('e'|'E') ('+'|'-')? ('0'..'9')+
	;

fragment
A3LETTER
	:	'A'..'Z' 
	|	'a'..'z'
	;

STRING	:	'"' (~'"')* '"'
	;

MINUS	
	:	'-'
	;

MULT	
	:	'*'
	;

NEWLINE	
	:	'\r'? '\n'
	;

PLUS	
	:	'+'
	;

SEMI	
	:	';'
	;
