%{
/*
 *                            COPYRIGHT
 *
 *  camv-rnd - electronics-related CAM viewer
 *  Copyright (C) 2019,2024 Tibor 'Igor2' Palinkas
 *
 *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *  Contact:
 *    Project page: http://repo.hu/projects/camv-rnd
 *    lead developer: http://repo.hu/projects/camv-rnd/contact.html
 *    mailing list: pcb-rnd (at) list.repo.hu (send "subscribe")
 */

#include <stdio.h>
#include "gcode_vm.h"
#include "gcode_lex.h"
%}

%lex-param { gcode_prg_t *ctx }
%parse-param { gcode_prg_t *ctx }

%union {
	double num;
	int chr;
}

%token <num> T_NUM
%token <num> T_DEC
%token <chr> T_CHR
%token T_NL T_LINENO
%token T_ACOS T_ASIN T_ATAN T_ABS T_COS T_SIN T_TAN
%token T_FIX T_FUP T_EXP T_LN T_ROUND T_SQRT

%left '+' '-'
%left '*' '/' T_MOD
%left UMINUS UPLUS
%left T_OR T_XOR T_AND
%left '#'

%%

program:
	line program
	| /* empty */
	;

line:
	  T_NL
	| T_LINENO T_DEC               { gcode_set_lineno(ctx, (int)$2); gcode_append(ctx, T_LINENO, $2); }
	                 codes T_NL    { gcode_delayed(ctx, GCP_DELAY_APPLY); gcode_delayed(ctx, GCP_DELAY_OFF); gcode_append(ctx, DO, -1); }
	|                              { gcode_append(ctx, T_LINENO, -1); ctx->lineno = -1; }
	  codes T_NL                   { gcode_delayed(ctx, GCP_DELAY_APPLY); gcode_delayed(ctx, GCP_DELAY_OFF); gcode_append(ctx, DO, -1); }
	;

codes:
	  gcode
	| gcode codes
	;

gcode:
	  T_CHR '[' expr ']'        { gcode_append(ctx, $1, -1); }
	| T_CHR '#' expr            { gcode_append(ctx, PARAM, 0); gcode_append(ctx, $1, -1)->do_pop = 1; }
	| T_CHR T_DEC               { gcode_append(ctx, $1, $2); }
	| T_CHR T_NUM               { gcode_append(ctx, $1, $2); }
	| T_CHR '-' T_NUM           { gcode_append(ctx, $1, -($3)); }
	| '#'
		{ gcode_delayed(ctx, GCP_DELAY_ON); } /* assignment needs to be executed at the end of the line (by the spec) */
		expr '=' expr
		{ gcode_append(ctx, ASSIGN, 0); gcode_delayed(ctx, GCP_DELAY_OFF); }
	;

expr:
	  '[' expr ']'
	| '-'                    {  gcode_append(ctx, PUSH_NUM, 0); }
	      expr %prec UMINUS  { gcode_append(ctx, SUB, 0); }
	| '+'                    { /* nothing to do */ }
	      expr %prec UPLUS
	| expr '+' expr          { gcode_append(ctx, ADD, 0); }
	| expr '-' expr          { gcode_append(ctx, SUB, 0); }
	| expr '*' expr          { gcode_append(ctx, MUL, 0); }
	| expr '/' expr          { gcode_append(ctx, DIV, 0); }
	| expr T_OR expr         { gcode_append(ctx, T_OR, 0); }
	| expr T_XOR expr        { gcode_append(ctx, T_XOR, 0); }
	| expr T_AND expr        { gcode_append(ctx, T_AND, 0); }
	| expr T_MOD expr        { gcode_append(ctx, T_MOD, 0); }
	| '#' expr               { gcode_append(ctx, PARAM, 0); }
	| T_ABS '[' expr ']'     { gcode_append(ctx, T_ABS, 0); }
	| T_ATAN '[' expr ']' '/'
	         '[' expr ']'    { gcode_append(ctx, T_ATAN, 0); }
	| T_ACOS '[' expr ']'    { gcode_append(ctx, T_ACOS, 0); }
	| T_ASIN '[' expr ']'    { gcode_append(ctx, T_ASIN, 0); }
	| T_COS '[' expr ']'     { gcode_append(ctx, T_COS, 0); }
	| T_SIN '[' expr ']'     { gcode_append(ctx, T_SIN, 0); }
	| T_TAN '[' expr ']'     { gcode_append(ctx, T_TAN, 0); }
	| T_FIX '[' expr ']'     { gcode_append(ctx, T_FIX, 0); }
	| T_FUP '[' expr ']'     { gcode_append(ctx, T_FUP, 0); }
	| T_EXP '[' expr ']'     { gcode_append(ctx, T_EXP, 0); }
	| T_LN '[' expr ']'      { gcode_append(ctx, T_LN, 0); }
	| T_ROUND '[' expr ']'   { gcode_append(ctx, T_ROUND, 0); }
	| T_SQRT '[' expr ']'    { gcode_append(ctx, T_SQRT, 0); }
	| T_NUM                  { gcode_append(ctx, PUSH_NUM, $1); }
	| T_DEC                  { gcode_append(ctx, PUSH_NUM, $1); }
	;

%%
