# HG changeset patch # User Mario de Sousa # Date 1313771637 -3600 # Node ID 0f24db96b519c16305888a1c0515121543351586 # Parent 17bffb57a8c59e66dc2d8cabd4c4633d085d7fcc Fixing automake configuration to work properly with flex and bison. diff -r 17bffb57a8c5 -r 0f24db96b519 configure --- a/configure Fri Jul 29 16:08:40 2011 +0100 +++ b/configure Fri Aug 19 17:33:57 2011 +0100 @@ -1825,11 +1825,11 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default - enum { N = $2 / 2 - 1 }; int main () { -static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; +static int test_array [1 - 2 * !(enum { N = $2 / 2 - 1 }; + 0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; test_array [0] = 0 ; @@ -1840,11 +1840,11 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default - enum { N = $2 / 2 - 1 }; int main () { -static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) +static int test_array [1 - 2 * !(enum { N = $2 / 2 - 1 }; + ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; test_array [0] = 0 @@ -6242,9 +6242,9 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" -config_commands="$ac_config_commands" +config_files="`echo $ac_config_files`" +config_headers="`echo $ac_config_headers`" +config_commands="`echo $ac_config_commands`" _ACEOF diff -r 17bffb57a8c5 -r 0f24db96b519 stage1_2/Makefile.am --- a/stage1_2/Makefile.am Fri Jul 29 16:08:40 2011 +0100 +++ b/stage1_2/Makefile.am Fri Aug 19 17:33:57 2011 +0100 @@ -1,16 +1,20 @@ include ../common.mk + + + +AM_YFLAGS = -d +AM_LFLAGS = -o$(LEX_OUTPUT_ROOT).c + + +# Make sure this header file is generated first (by bison), as it is included +# by other C++ code that will also be compiled. +BUILT_SOURCES = iec_bison.h + lib_LIBRARIES = libstage1_2.a - -iec.y.cc: iec.y - $(YACC) -d -v -o iec.y.cc iec.y - -iec.flex.cc: iec.flex - $(LEX) -o iec.flex.cc iec.flex - libstage1_2_a_SOURCES = \ - iec.flex.cc \ - iec.y.cc \ + iec_flex.ll \ + iec_bison.yy \ stage1_2.cc libstage1_2_a_CPPFLAGS = -DDEFAULT_LIBDIR='"lib"' -I../../absyntax diff -r 17bffb57a8c5 -r 0f24db96b519 stage1_2/Makefile.in --- a/stage1_2/Makefile.in Fri Jul 29 16:08:40 2011 +0100 +++ b/stage1_2/Makefile.in Fri Aug 19 17:33:57 2011 +0100 @@ -33,7 +33,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : DIST_COMMON = $(srcdir)/../common.mk $(srcdir)/Makefile.am \ - $(srcdir)/Makefile.in + $(srcdir)/Makefile.in iec_bison.cc iec_bison.h iec_flex.cc subdir = stage1_2 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac @@ -70,8 +70,9 @@ ARFLAGS = cru libstage1_2_a_AR = $(AR) $(ARFLAGS) libstage1_2_a_LIBADD = -am_libstage1_2_a_OBJECTS = libstage1_2_a-iec.flex.$(OBJEXT) \ - libstage1_2_a-iec.y.$(OBJEXT) libstage1_2_a-stage1_2.$(OBJEXT) +am_libstage1_2_a_OBJECTS = libstage1_2_a-iec_flex.$(OBJEXT) \ + libstage1_2_a-iec_bison.$(OBJEXT) \ + libstage1_2_a-stage1_2.$(OBJEXT) libstage1_2_a_OBJECTS = $(am_libstage1_2_a_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/config depcomp = $(SHELL) $(top_srcdir)/config/depcomp @@ -82,6 +83,13 @@ CXXLD = $(CXX) CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ +LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) +YLWRAP = $(top_srcdir)/config/ylwrap +YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS) +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libstage1_2_a_SOURCES) DIST_SOURCES = $(libstage1_2_a_SOURCES) ETAGS = etags @@ -185,17 +193,24 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CXXFLAGS = -g -Wall -Wpointer-arith -Wwrite-strings -Wno-unused +AM_YFLAGS = -d +AM_LFLAGS = -o$(LEX_OUTPUT_ROOT).c + +# Make sure this header file is generated first (by bison), as it is included +# by other C++ code that will also be compiled. +BUILT_SOURCES = iec_bison.h lib_LIBRARIES = libstage1_2.a libstage1_2_a_SOURCES = \ - iec.flex.cc \ - iec.y.cc \ + iec_flex.ll \ + iec_bison.yy \ stage1_2.cc libstage1_2_a_CPPFLAGS = -DDEFAULT_LIBDIR='"lib"' -I../../absyntax -all: all-am +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: -.SUFFIXES: .cc .o .obj +.SUFFIXES: .cc .ll .o .obj .yy $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/../common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ @@ -258,6 +273,11 @@ clean-libLIBRARIES: -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES) +iec_bison.h: iec_bison.cc + @if test ! -f $@; then \ + rm -f iec_bison.cc; \ + $(MAKE) $(AM_MAKEFLAGS) iec_bison.cc; \ + else :; fi libstage1_2.a: $(libstage1_2_a_OBJECTS) $(libstage1_2_a_DEPENDENCIES) -rm -f libstage1_2.a $(libstage1_2_a_AR) libstage1_2.a $(libstage1_2_a_OBJECTS) $(libstage1_2_a_LIBADD) @@ -269,8 +289,8 @@ distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstage1_2_a-iec.flex.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstage1_2_a-iec.y.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstage1_2_a-iec_bison.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstage1_2_a-iec_flex.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstage1_2_a-stage1_2.Po@am__quote@ .cc.o: @@ -287,33 +307,33 @@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` -libstage1_2_a-iec.flex.o: iec.flex.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libstage1_2_a-iec.flex.o -MD -MP -MF $(DEPDIR)/libstage1_2_a-iec.flex.Tpo -c -o libstage1_2_a-iec.flex.o `test -f 'iec.flex.cc' || echo '$(srcdir)/'`iec.flex.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libstage1_2_a-iec.flex.Tpo $(DEPDIR)/libstage1_2_a-iec.flex.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='iec.flex.cc' object='libstage1_2_a-iec.flex.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libstage1_2_a-iec.flex.o `test -f 'iec.flex.cc' || echo '$(srcdir)/'`iec.flex.cc - -libstage1_2_a-iec.flex.obj: iec.flex.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libstage1_2_a-iec.flex.obj -MD -MP -MF $(DEPDIR)/libstage1_2_a-iec.flex.Tpo -c -o libstage1_2_a-iec.flex.obj `if test -f 'iec.flex.cc'; then $(CYGPATH_W) 'iec.flex.cc'; else $(CYGPATH_W) '$(srcdir)/iec.flex.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libstage1_2_a-iec.flex.Tpo $(DEPDIR)/libstage1_2_a-iec.flex.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='iec.flex.cc' object='libstage1_2_a-iec.flex.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libstage1_2_a-iec.flex.obj `if test -f 'iec.flex.cc'; then $(CYGPATH_W) 'iec.flex.cc'; else $(CYGPATH_W) '$(srcdir)/iec.flex.cc'; fi` - -libstage1_2_a-iec.y.o: iec.y.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libstage1_2_a-iec.y.o -MD -MP -MF $(DEPDIR)/libstage1_2_a-iec.y.Tpo -c -o libstage1_2_a-iec.y.o `test -f 'iec.y.cc' || echo '$(srcdir)/'`iec.y.cc -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libstage1_2_a-iec.y.Tpo $(DEPDIR)/libstage1_2_a-iec.y.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='iec.y.cc' object='libstage1_2_a-iec.y.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libstage1_2_a-iec.y.o `test -f 'iec.y.cc' || echo '$(srcdir)/'`iec.y.cc - -libstage1_2_a-iec.y.obj: iec.y.cc -@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libstage1_2_a-iec.y.obj -MD -MP -MF $(DEPDIR)/libstage1_2_a-iec.y.Tpo -c -o libstage1_2_a-iec.y.obj `if test -f 'iec.y.cc'; then $(CYGPATH_W) 'iec.y.cc'; else $(CYGPATH_W) '$(srcdir)/iec.y.cc'; fi` -@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libstage1_2_a-iec.y.Tpo $(DEPDIR)/libstage1_2_a-iec.y.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='iec.y.cc' object='libstage1_2_a-iec.y.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libstage1_2_a-iec.y.obj `if test -f 'iec.y.cc'; then $(CYGPATH_W) 'iec.y.cc'; else $(CYGPATH_W) '$(srcdir)/iec.y.cc'; fi` +libstage1_2_a-iec_flex.o: iec_flex.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libstage1_2_a-iec_flex.o -MD -MP -MF $(DEPDIR)/libstage1_2_a-iec_flex.Tpo -c -o libstage1_2_a-iec_flex.o `test -f 'iec_flex.cc' || echo '$(srcdir)/'`iec_flex.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libstage1_2_a-iec_flex.Tpo $(DEPDIR)/libstage1_2_a-iec_flex.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='iec_flex.cc' object='libstage1_2_a-iec_flex.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libstage1_2_a-iec_flex.o `test -f 'iec_flex.cc' || echo '$(srcdir)/'`iec_flex.cc + +libstage1_2_a-iec_flex.obj: iec_flex.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libstage1_2_a-iec_flex.obj -MD -MP -MF $(DEPDIR)/libstage1_2_a-iec_flex.Tpo -c -o libstage1_2_a-iec_flex.obj `if test -f 'iec_flex.cc'; then $(CYGPATH_W) 'iec_flex.cc'; else $(CYGPATH_W) '$(srcdir)/iec_flex.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libstage1_2_a-iec_flex.Tpo $(DEPDIR)/libstage1_2_a-iec_flex.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='iec_flex.cc' object='libstage1_2_a-iec_flex.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libstage1_2_a-iec_flex.obj `if test -f 'iec_flex.cc'; then $(CYGPATH_W) 'iec_flex.cc'; else $(CYGPATH_W) '$(srcdir)/iec_flex.cc'; fi` + +libstage1_2_a-iec_bison.o: iec_bison.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libstage1_2_a-iec_bison.o -MD -MP -MF $(DEPDIR)/libstage1_2_a-iec_bison.Tpo -c -o libstage1_2_a-iec_bison.o `test -f 'iec_bison.cc' || echo '$(srcdir)/'`iec_bison.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libstage1_2_a-iec_bison.Tpo $(DEPDIR)/libstage1_2_a-iec_bison.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='iec_bison.cc' object='libstage1_2_a-iec_bison.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libstage1_2_a-iec_bison.o `test -f 'iec_bison.cc' || echo '$(srcdir)/'`iec_bison.cc + +libstage1_2_a-iec_bison.obj: iec_bison.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libstage1_2_a-iec_bison.obj -MD -MP -MF $(DEPDIR)/libstage1_2_a-iec_bison.Tpo -c -o libstage1_2_a-iec_bison.obj `if test -f 'iec_bison.cc'; then $(CYGPATH_W) 'iec_bison.cc'; else $(CYGPATH_W) '$(srcdir)/iec_bison.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libstage1_2_a-iec_bison.Tpo $(DEPDIR)/libstage1_2_a-iec_bison.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='iec_bison.cc' object='libstage1_2_a-iec_bison.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libstage1_2_a-iec_bison.obj `if test -f 'iec_bison.cc'; then $(CYGPATH_W) 'iec_bison.cc'; else $(CYGPATH_W) '$(srcdir)/iec_bison.cc'; fi` libstage1_2_a-stage1_2.o: stage1_2.cc @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libstage1_2_a-stage1_2.o -MD -MP -MF $(DEPDIR)/libstage1_2_a-stage1_2.Tpo -c -o libstage1_2_a-stage1_2.o `test -f 'stage1_2.cc' || echo '$(srcdir)/'`stage1_2.cc @@ -329,6 +349,12 @@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstage1_2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libstage1_2_a-stage1_2.obj `if test -f 'stage1_2.cc'; then $(CYGPATH_W) 'stage1_2.cc'; else $(CYGPATH_W) '$(srcdir)/stage1_2.cc'; fi` +.ll.cc: + $(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE) + +.yy.cc: + $(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE) + ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -412,13 +438,15 @@ fi; \ done check-am: all-am -check: check-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(LIBRARIES) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done -install: install-am +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am @@ -443,6 +471,10 @@ maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." + -rm -f iec_bison.cc + -rm -f iec_bison.h + -rm -f iec_flex.cc + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libLIBRARIES mostlyclean-am @@ -512,7 +544,7 @@ uninstall-am: uninstall-libLIBRARIES -.MAKE: install-am install-strip +.MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libLIBRARIES ctags distclean distclean-compile \ @@ -528,12 +560,6 @@ uninstall-am uninstall-libLIBRARIES -iec.y.cc: iec.y - $(YACC) -d -v -o iec.y.cc iec.y - -iec.flex.cc: iec.flex - $(LEX) -o iec.flex.cc iec.flex - # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff -r 17bffb57a8c5 -r 0f24db96b519 stage1_2/iec.flex --- a/stage1_2/iec.flex Fri Jul 29 16:08:40 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1719 +0,0 @@ -/* - * matiec - a compiler for the programming languages defined in IEC 61131-3 - * - * Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt) - * - * 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 . - * - * - * This code is made available on the understanding that it will not be - * used in safety-critical situations without a full and competent review. - */ - -/* - * An IEC 61131-3 compiler. - * - * Based on the - * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) - * - */ - -/* - * Stage 1 - * ======= - * - * This file contains the lexical tokens definitions, from which - * the flex utility will generate a lexical parser function. - */ - - - - -/*****************************/ -/* Lexical Parser Options... */ -/*****************************/ - -/* The lexical analyser will never work in interactive mode, - * i.e., it will only process programs saved to files, and never - * programs being written inter-actively by the user. - * This option saves the resulting parser from calling the - * isatty() function, that seems to be generating some compile - * errors under some (older?) versions of flex. - */ -%option never-interactive - -/* Have the lexical analyser use a 'char *yytext' instead of an - * array of char 'char yytext[??]' to store the lexical token. - */ -%pointer - - -/* Have the lexical analyser ignore the case of letters. - * This will occur for all the tokens and keywords, but - * the resulting text handed up to the syntax parser - * will not be changed, and keep the original case - * of the letters in the input file. - */ -%option case-insensitive - -/* Have the generated lexical analyser keep track of the - * line number it is currently analysing. - * This is used to pass up to the syntax parser - * the number of the line on which the current - * token was found. It will enable the syntax parser - * to generate more informatve error messages... - */ -%option yylineno - -/* required for the use of the yy_pop_state() and - * yy_push_state() functions - */ -%option stack - -/* The '%option stack' also requests the inclusion of - * the yy_top_state(), however this function is not - * currently being used. This means that the compiler - * is complaining about the existance of this function. - * The following option removes the yy_top_state() - * function from the resulting c code, so the compiler - * no longer complains. - */ -%option noyy_top_state - -/* We will not be using unput() in our flex code... */ -%option nounput - -/**************************************************/ -/* External Variable and Function declarations... */ -/**************************************************/ - - -%{ -/* Define TEST_MAIN to include a main() function. - * Useful for testing the parser generated by flex. - */ -/* -#define TEST_MAIN -*/ -/* If lexical parser is compiled by itself, we need to define the following - * constant to some string. Under normal circumstances LIBDIRECTORY is set - * in the syntax parser header file... - */ -#ifdef TEST_MAIN -#define DEFAULT_LIBDIR "just_testing" -#endif - - - -/* Required for strdup() */ -#include - -/* Required only for the declaration of abstract syntax classes - * (class symbol_c; class token_c; class list_c;) - * These will not be used in flex, but the token type union defined - * in iec.hh contains pointers to these classes, so we must include - * it here. - */ -#include "../absyntax/absyntax.hh" - - -/* generated by bison. - * Contains the definition of the token constants, and the - * token value type YYSTYPE (in our case, a 'const char *') - */ -#include "iec.y.hh" -#include "stage1_2_priv.hh" - - -/* Variable defined by the bison parser, - * where the value of the tokens will be stored - */ -extern YYSTYPE yylval; - -/* The name of the file currently being parsed... - * This variable is declared and read from the code generated by bison! - * Note that flex accesses and updates this global variable - * apropriately whenever it comes across an (*#include *) - * directive... - */ -/* - NOTE: already defined in iec.y.hh -extern const char *current_filename; -*/ - - -/* We will not be using unput() in our flex code... */ -/* NOTE: it seems that this #define is no longer needed, It has been - * replaced by %option nounput. - * Should we simply delete it? - * For now leave it in, in case someone is using an old version of flex. - * In any case, the most harm that can result in a warning message - * when compiling iec.flex.c: - * warning: ‘void yyunput(int, char*)’ defined but not used - */ -#define YY_NO_UNPUT - -/* Variable defined by the bison parser. - * It must be initialised with the location - * of the token being parsed. - * This is only needed if we want to keep - * track of the locations, in order to give - * more meaningful error messages! - */ -extern YYLTYPE yylloc; - -#define YY_INPUT(buf,result,max_size) {\ - result = GetNextChar(buf, max_size);\ - if ( result <= 0 )\ - result = YY_NULL;\ - } - - -/* A counter to track the order by which each token is processed. - * NOTE: This counter is not exactly linear (i.e., it does not get incremented by 1 for each token). - * i.e.. it may get incremented by more than one between two consecutive tokens. - * This is due to the fact that the counter gets incremented every 'user action' in flex, - * however not every user action will result in a token being passed to bison. - * Nevertheless this is still OK, as we are only interested in the relative - * ordering of tokens... - */ -static long int current_order = 0; - - -/* Macro that is executed for every action. - * We use it to pass the location of the token - * back to the bison parser... - */ -#define YY_USER_ACTION {\ - yylloc.first_line = current_tracking->lineNumber; \ - yylloc.first_column = current_tracking->currentTokenStart; \ - yylloc.first_file = current_filename; \ - yylloc.first_order = current_order; \ - yylloc.last_line = current_tracking->lineNumber; \ - yylloc.last_column = current_tracking->currentChar - 1; \ - yylloc.last_file = current_filename; \ - yylloc.last_order = current_order; \ - current_tracking->currentTokenStart = current_tracking->currentChar; \ - current_order++; \ - } - - -/* Since this lexical parser we defined only works in ASCII based - * systems, we might as well make sure it is being compiled on - * one... - * Lets check a few random characters... - */ -#if (('a' != 0x61) || ('A' != 0x41) || ('z' != 0x7A) || ('Z' != 0x5A) || \ - ('0' != 0x30) || ('9' != 0x39) || ('(' != 0x28) || ('[' != 0x5B)) -#error This lexical analyser is not portable to a non ASCII based system. -#endif - - -/* Function only called from within flex, but defined - * in iec.y! - * We declare it here... - * - * Search for a symbol in either of the two symbol tables - * and return the token id of the first symbol found. - * Searches first in the variables, and only if not found - * does it continue searching in the library elements - */ -//token_id_t get_identifier_token(const char *identifier_str); -int get_identifier_token(const char *identifier_str); -%} - - -/***************************************************/ -/* Forward Declaration of functions defined later. */ -/***************************************************/ - -%{ -/* return all the text in the current token back to the input stream. */ -void unput_text(unsigned int n); -%} - - - -/****************************/ -/* Lexical Parser States... */ -/****************************/ - -/* NOTE: Our psrser can parse st or il code, intermixed - * within the same file. - * With IL we come across the issue of the EOL (end of line) token. - * ST, and the declaration parts of IL do not use this token! - * If the lexical analyser were to issue this token during ST - * language parsing, or during the declaration of data types, - * function headers, etc. in IL, the syntax parser would crash. - * - * We can solve this issue using one of three methods: - * (1) Augment all the syntax that does not accept the EOL - * token to simply ignore it. This makes the syntax - * definition (in iec.y) very cluttered! - * (2) Let the lexical parser figure out which language - * it is parsing, and decide whether or not to issue - * the EOL token. This requires the lexical parser - * to have knowledge of the syntax!, making for a poor - * overall organisation of the code. It would also make it - * very difficult to understand the lexical parser as it - * would use several states, and a state machine to transition - * between the states. The state transitions would be - * intermingled with the lexical parser defintion! - * (3) Use a mixture of (1) and (2). The lexical analyser - * merely distinguishes between function headers and function - * bodies, but no longer makes a distinction between il and - * st language bodies. When parsing a body, it will return - * the EOL token. In other states '\n' will be ignored as - * whitespace. - * The ST language syntax has been augmented in the syntax - * parser configuration to ignore any EOL tokens that it may - * come across! - * This option has both drawbacks of option (1) and (2), but - * much less intensely. - * The syntax that gets cluttered is limited to the ST statements - * (which is rather limited, compared to the function headers and - * data type declarations, etc...), while the state machine in - * the lexical parser becomes very simple. All state transitions - * can be handled within the lexical parser by itself, and can be - * easily identified. Thus knowledge of the syntax required by - * the lexical parser is very limited! - * - * Amazingly enough, I (Mario) got to implement option (3) - * at first, requiring two basic states, decl and body. - * The lexical parser will enter the body state when - * it is parsing the body of a function/program/function block. The - * state transition is done when we find a VAR_END that is not followed - * by a VAR! This is the syntax knowledge that gets included in the - * lexical analyser with this option! - * Unfortunately, getting the st syntax parser to ignore EOL anywhere - * where they might appear leads to conflicts. This is due to the fact - * that the syntax parser uses the single look-ahead token to remove - * possible conflicts. When we insert a possible EOL, the single - * look ahead token becomes the EOL, which means the potential conflicts - * could no longer be resolved. - * Removing these conflicts would make the st syntax parser very convoluted, - * and adding the extraneous EOL would make it very cluttered. - * This option was therefore dropped in favour of another! - * - * I ended up implementing (2). Unfortunately the lexical analyser can - * not easily distinguish between il and st code, since function - * calls in il are very similar to function block calls in st. - * We therefore use an extra 'body' state. When the lexical parser - * finds that last END_VAR, it enters the body state. This state - * must figure out what language is being parsed from the first few - * tokens, and switch to the correct state (st, il or sfc) according to the - * language. This means that we insert quite a bit of knowledge of the - * syntax of the languages into the lexical parser. This is ugly, but it - * works, and at least it is possible to keep all the state changes together - * to make it easier to remove them later on if need be. - * Once the language being parsed has been identified, - * the body state returns any matched text back to the buffer with unput(), - * to be later matched correctly by the apropriate language parser (st, il or sfc). - * - * Aditionally, in sfc state it may further recursively enter the body state - * once again. This is because an sfc body may contain ACTIONS, which are then - * written in one of the three languages (ST, IL or SFC), so once again we need - * to figure out which language the ACTION in the SFC was written in. We already - * ahve all that done in the body state, so we recursively transition to the body - * state once again. - * Note that in this case, when coming out of the st/il state (whichever language - * the action was written in) the sfc state will become active again. This is done by - * pushing and poping the previously active state! - * - * The sfc_qualifier_state is required because when parsing actions within an - * sfc, we will be expecting action qualifiers (N, P, R, S, DS, SD, ...). In order - * to bison to work correctly, these qualifiers must be returned as tokens. However, - * these tokens are not reserved keywords, which means it should be possible to - * define variables/functions/FBs with any of these names (including - * S and R which are special because they are also IL operators). So, when we are not - * expecting any action qualifiers, flex does not return these tokens, and is free - * to interpret them as previously defined variables/functions/... as the case may be. - * - * The state machine has 7 possible states (INITIAL, config, decl, body, st, il, sfc) - * Possible state changes are: - * INITIAL -> goto(decl_state) - * (when a FUNCTION, FUNCTION_BLOCK, or PROGRAM is found, - * and followed by a VAR declaration) - * INITIAL -> goto(body_state) - * (when a FUNCTION, FUNCTION_BLOCK, or PROGRAM is found, - * and _not_ followed by a VAR declaration) - * (This transition is actually commented out, since the syntax - * does not allow the declaration of functions, FBs, or programs - * without any VAR declaration!) - * INITIAL -> goto(config_state) - * (when a CONFIGURATION is found) - * decl_state -> push(decl_state); goto(body_state) - * (when the last END_VAR is found, i.e. the function body starts) - * decl_state -> push(decl_state); goto(sfc_state) - * (when it figures out it is parsing sfc language) - * body_state -> goto(st_state) - * (when it figures out it is parsing st language) - * body_state -> goto(il_state) - * (when it figures out it is parsing il language) - * st_state -> pop() - * (when a END_FUNCTION, END_FUNCTION_BLOCK, END_PROGRAM, - * END_ACTION or END_TRANSITION is found) - * il_state -> pop() - * (when a END_FUNCTION, END_FUNCTION_BLOCK, END_PROGRAM, - * END_ACTION or END_TRANSITION is found) - * decl_state -> goto(INITIAL) - * (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found) - * sfc_state -> goto(INITIAL) - * (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found) - * config_state -> goto(INITIAL) - * (when a END_CONFIGURATION is found) - * sfc_state -> push(sfc_state); goto(body_state) - * (when parsing an action. This transition is requested by bison) - * sfc_state -> push(sfc_state); goto(sfc_qualifier_state) - * (when expecting an action qualifier. This transition is requested by bison) - * sfc_qualifier_state -> pop() - * (when no longer expecting an action qualifier. This transition is requested by bison) - * config_state -> push(config_state); goto(task_init_state) - * (when parsing a task initialisation. This transition is requested by bison) - * task_init_state -> pop() - * (when no longer parsing task initialisation parameters. This transition is requested by bison) - * - */ - - -/* we are parsing a configuration. */ -%s config_state - -/* Inside a configuration, we are parsing a task initialisation parameters */ -/* This means that PRIORITY, SINGLE and INTERVAL must be handled as - * tokens, and not as possible identifiers. Note that the above words - * are not keywords. - */ -%s task_init_state - -/* we are parsing a function, program or function block declaration */ -%s decl_state - -/* we will be parsing a function body. Whether il/st is remains unknown */ -%x body_state - -/* we are parsing il code -> flex must return the EOL tokens! */ -%s il_state - -/* we are parsing st code -> flex must not return the EOL tokens! */ -%s st_state - -/* we are parsing sfc code -> flex must not return the EOL tokens! */ -%s sfc_state - -/* we are parsing sfc code, and expecting an action qualifier. */ -%s sfc_qualifier_state - -/* we are parsing sfc code, and expecting the priority token. */ -%s sfc_priority_state - - - - -/*******************/ -/* File #include's */ -/*******************/ - -/* We extend the IEC 61131-3 standard syntax to allow inclusion - * of other files, using the IEC 61131-3 pragma directive... - * The accepted syntax is: - * {#include ""} - */ - -/* the "include" states are used for picking up the name of an include file */ -%x include_beg -%x include_filename -%x include_end - - -file_include_pragma_filename [^\"]* -file_include_pragma_beg "{#include"{st_whitespace_only}\" -file_include_pragma_end \"{st_whitespace_only}"}" -file_include_pragma {file_include_pragma_beg}{file_include_pragma_filename}{file_include_pragma_end} - - -%{ -#define MAX_INCLUDE_DEPTH 16 - -typedef struct { - YY_BUFFER_STATE buffer_state; - tracking_t* env; - const char *filename; - } include_stack_t; - -tracking_t* current_tracking; -include_stack_t include_stack[MAX_INCLUDE_DEPTH]; -int include_stack_ptr = 0; - -const char *INCLUDE_DIRECTORIES[] = { - DEFAULT_LIBDIR, - ".", - "/lib", - "/usr/lib", - "/usr/lib/iec", - NULL /* must end with NULL!! */ - }; - -%} - - - -/*****************************/ -/* Prelimenary constructs... */ -/*****************************/ - -/* In order to allow the declaration of POU prototypes (Function, FB, Program, ...), - * especially the prototypes of Functions and FBs defined in the standard - * (i.e. standard functions and FBs), we extend the IEC 61131-3 standard syntax - * with two pragmas to indicate that the code is to be parsed (going through the - * lexical, syntactical, and semantic analysers), but no code is to be generated. - * - * The accepted syntax is: - * {no_code_generation begin} - * ... prototypes ... - * {no_code_generation end} - * - * When parsing these prototypes the abstract syntax tree will be populated as usual, - * allowing the semantic analyser to correctly analyse the semantics of calls to these - * functions/FBs. However, stage4 will simply ignore all IEC61131-3 code - * between the above two pragmas. - */ - -disable_code_generation_pragma "{disable code generation}" -enable_code_generation_pragma "{enable code generation}" - - -/* Any other pragma... */ - -pragma "{"[^}]*"}" - -/* NOTE: this seemingly unnecessary complex definition is required - * to be able to eat up comments such as: - * '(* Testing... ! ***** ******)' - * without using the trailing context command in flex (/{context}) - * since {comment} itself will later be used with - * trailing context ({comment}/{context}) - */ -not_asterisk [^*] -not_close_parenthesis_nor_asterisk [^*)] -asterisk "*" -comment_text {not_asterisk}|(({asterisk}+){not_close_parenthesis_nor_asterisk}) - -comment "(*"({comment_text}*)({asterisk}+)")" - - -/* -3.1 Whitespace - (NOTE: Whitespace IS clearly defined, to include newline!!! See section 2.1.4!!!) - No definition of whitespace is given, in other words, the characters that may be used to seperate language tokens are not pecisely defined. One may nevertheless make an inteligent guess of using the space (' '), and other characters also commonly considered whitespace in other programming languages (horizontal tab, vertical tab, form feed, etc.). - The main question is whether the newline character should be considered whitespace. IL language statements use an EOL token (End Of Line) to distinguish between some language constructs. The EOL token itself is openly defined as "normally consist[ing] of the 'paragraph separator' ", leaving the final choice open to each implemention. If we choose the newline character to represent the EOL token, it may then not be considered whitespace. - On the other hand, some examples that come in a non-normative annex of the specification allow function declarations to span multiple3.1 Whitespace - (NOTE: Whitespace IS clearly defined, to include newline!!! See section 2.1.4!!!) - No definition of whitespace is given, in other words, the characters that may be used to seperate language tokens are not pecisely defined. One may nevertheless make an inteligent guess of using the space (' '), and other characters also commonly considered whitespace in other programming languages (horizontal tab, vertical tab, form feed, etc.). - The main question is whether the newline character should be considered whitespace. IL language statements use an EOL token (End Of Line) to distinguish between some language constructs. The EOL token itself is openly defined as "normally consist[ing] of the 'paragraph separator' ", leaving the final choice open to each implemention. If we choose the newline character to represent the EOL token, it may then not be considered whitespace. - On the other hand, some examples that come in a non-normative annex of the specification allow function declarations to span multiple lines, which means that the newline character is being considered as whitespace. - Our implementation works around this issue by including the new line character in the whitespace while parsing function declarations and the ST language, and parsing it as the EOL token only while parsing IL language statements. This requires the use of a state machine in the lexical parser that needs at least some knowledge of the syntax itself. -*/ -/* NOTE: Our definition of whitespace will only work in ASCII! - * - * Since the IL language needs to know the location of newline - * (token EOL -> '\n' ), we need one definition of whitespace - * for each language... - */ -/* - * NOTE: we cannot use - * st_whitespace [:space:]* - * since we use {st_whitespace} as trailing context. In our case - * this would not constitute "dangerous trailing context", but the - * lexical generator (i.e. flex) does not know this (since it does - * not know which characters belong to the set [:space:]), and will - * generate a "dangerous trailing context" warning! - * We use this alternative just to stop the flex utility from - * generating the invalid (in this case) warning... - */ - -st_whitespace_only [ \f\n\r\t\v]* -il_whitespace_only [ \f\r\t\v]* - -st_whitespace_text {st_whitespace_only}|{comment}|{pragma} -il_whitespace_text {il_whitespace_only}|{comment}|{pragma} - -st_whitespace {st_whitespace_text}* -il_whitespace {il_whitespace_text}* - -st_whitespace_text_no_pragma {st_whitespace_only}|{comment} -il_whitespace_text_no_pragma {il_whitespace_only}|{comment} - -st_whitespace_no_pragma {st_whitespace_text_no_pragma}* -il_whitespace_no_pragma {il_whitespace_text_no_pragma}* - -qualified_identifier {identifier}(\.{identifier})* - - - -/*****************************************/ -/* B.1.1 Letters, digits and identifiers */ -/*****************************************/ -/* NOTE: The following definitions only work if the host computer - * is using the ASCII maping. For e.g., with EBCDIC [A-Z] - * contains non-alphabetic characters! - * The correct way of doing it would be to use - * the [:upper:] etc... definitions. - * - * Unfortunately, further on we need all printable - * characters (i.e. [:print:]), but excluding '$'. - * Flex does not allow sets to be composed by excluding - * elements. Sets may only be constructed by adding new - * elements, which means that we have to revert to - * [\x20\x21\x23\x25\x26\x28-x7E] for the definition - * of the printable characters with the required exceptions. - * The above also implies the use of ASCII, but now we have - * no way to work around it| - * - * The conclusion is that our parser is limited to ASCII - * based host computers!! - */ -letter [A-Za-z] -digit [0-9] -octal_digit [0-7] -hex_digit {digit}|[A-F] -identifier ({letter}|(_({letter}|{digit})))((_?({letter}|{digit}))*) - -/*******************/ -/* B.1.2 Constants */ -/*******************/ - -/******************************/ -/* B.1.2.1 Numeric literals */ -/******************************/ -integer {digit}((_?{digit})*) -binary_integer 2#{bit}((_?{bit})*) -bit [0-1] -octal_integer 8#{octal_digit}((_?{octal_digit})*) -hex_integer 16#{hex_digit}((_?{hex_digit})*) -exponent [Ee]([+-]?){integer} -/* The correct definition for real would be: - * real {integer}\.{integer}({exponent}?) - * - * Unfortunately, the spec also defines fixed_point (B 1.2.3.1) as: - * fixed_point {integer}\.{integer} - * - * This means that {integer}\.{integer} could be interpreted - * as either a fixed_point or a real. - * I have opted to interpret {integer}\.{integer} as a fixed_point. - * In order to do this, the definition of real has been changed to: - * real {integer}\.{integer}{exponent} - * - * This means that the syntax parser now needs to define a real to be - * either a real_token or a fixed_point_token! - */ -real {integer}\.{integer}{exponent} - - -/*******************************/ -/* B.1.2.2 Character Strings */ -/*******************************/ -/* -common_character_representation := - -|'$$' -|'$L'|'$N'|'$P'|'$R'|'$T' -|'$l'|'$n'|'$p'|'$r'|'$t' - -NOTE: $ = 0x24 - " = 0x22 - ' = 0x27 - - printable chars in ASCII: 0x20-0x7E -*/ - -esc_char_u $L|$N|$P|$R|$T -esc_char_l $l|$n|$p|$r|$t -esc_char $$|{esc_char_u}|{esc_char_l} -double_byte_char (${hex_digit}{hex_digit}{hex_digit}{hex_digit}) -single_byte_char (${hex_digit}{hex_digit}) - -/* WARNING: - * This definition is only valid in ASCII... - * - * Flex includes the function print_char() that defines - * all printable characters portably (i.e. whatever character - * encoding is currently being used , ASCII, EBCDIC, etc...) - * Unfortunately, we cannot generate the definition of - * common_character_representation portably, since flex - * does not allow definition of sets by subtracting - * elements in one set from another set. - * This means we must build up the defintion of - * common_character_representation using only set addition, - * which leaves us with the only choice of defining the - * characters non-portably... - */ -common_character_representation [\x20\x21\x23\x25\x26\x28-\x7E]|{esc_char} -double_byte_character_representation $\"|'|{double_byte_char}|{common_character_representation} -single_byte_character_representation $'|\"|{single_byte_char}|{common_character_representation} - - -double_byte_character_string \"({double_byte_character_representation}*)\" -single_byte_character_string '({single_byte_character_representation}*)' - - -/************************/ -/* B 1.2.3.1 - Duration */ -/************************/ -fixed_point {integer}\.{integer} - -fixed_point_d {fixed_point}d -integer_d {integer}d - -fixed_point_h {fixed_point}h -integer_h {integer}h - -fixed_point_m {fixed_point}m -integer_m {integer}m - -fixed_point_s {fixed_point}s -integer_s {integer}s - -fixed_point_ms {fixed_point}ms -integer_ms {integer}ms - - -/********************************************/ -/* B.1.4.1 Directly Represented Variables */ -/********************************************/ -/* The correct definition, if the standard were to be followed... */ - -location_prefix [IQM] -size_prefix [XBWDL] -direct_variable_standard %{location_prefix}({size_prefix}?){integer}((.{integer})*) - - -/* For the MatPLC, we will accept % - * as a direct variable, this being mapped onto the MatPLC point - * named - */ -/* TODO: we should not restrict it to only the accepted syntax - * of as specified by the standard. MatPLC point names - * have a more permissive syntax. - * - * e.g. "P__234" - * Is a valid MatPLC point name, but not a valid !! - * The same happens with names such as "333", "349+23", etc... - * How can we handle these more expressive names in our case? - * Remember that some direct variable may remain anonymous, with - * declarations such as: - * VAR - * AT %I3 : BYTE := 255; - * END_VAR - * in which case we are currently using "%I3" as the variable - * name. - */ -direct_variable_matplc %{identifier} - -direct_variable {direct_variable_standard}|{direct_variable_matplc} - -/******************************************/ -/* B 1.4.3 - Declaration & Initialisation */ -/******************************************/ -incompl_location %[IQM]\* - - - - -%% - /* fprintf(stderr, "flex: state %d\n", YY_START); */ - - /*****************************************************/ - /*****************************************************/ - /*****************************************************/ - /***** *****/ - /***** *****/ - /***** F I R S T T H I N G S F I R S T *****/ - /***** *****/ - /***** *****/ - /*****************************************************/ - /*****************************************************/ - /*****************************************************/ - - /***********************************************************/ - /* Handle requests sent by bison for flex to change state. */ - /***********************************************************/ - if (get_goto_body_state()) { - yy_push_state(body_state); - rst_goto_body_state(); - } - - if (get_goto_sfc_qualifier_state()) { - yy_push_state(sfc_qualifier_state); - rst_goto_sfc_qualifier_state(); - } - - if (get_goto_sfc_priority_state()) { - yy_push_state(sfc_priority_state); - rst_goto_sfc_priority_state(); - } - - if (get_goto_task_init_state()) { - yy_push_state(task_init_state); - rst_goto_task_init_state(); - } - - if (get_pop_state()) { - yy_pop_state(); - rst_pop_state(); - } - - /***************************/ - /* Handle the pragmas! */ - /***************************/ - - /* We start off by searching for the pragmas we handle in the lexical parser. */ -{file_include_pragma} unput_text(0); yy_push_state(include_beg); - - /* Pragmas sent to syntax analyser (bison) */ -{disable_code_generation_pragma} return disable_code_generation_pragma_token; -{enable_code_generation_pragma} return enable_code_generation_pragma_token; -{disable_code_generation_pragma} return disable_code_generation_pragma_token; -{enable_code_generation_pragma} return enable_code_generation_pragma_token; - - /* Any other pragma we find, we just pass it up to the syntax parser... */ - /* Note that the state is exclusive, so we have to include it here too. */ -{pragma} {/* return the pragmma without the enclosing '{' and '}' */ - yytext[strlen(yytext)-1] = '\0'; - yylval.ID=strdup(yytext+1); - return pragma_token; - } -{pragma} {/* return the pragmma without the enclosing '{' and '}' */ - yytext[strlen(yytext)-1] = '\0'; - yylval.ID=strdup(yytext+1); - return pragma_token; - } - - - /*********************************/ - /* Handle the file includes! */ - /*********************************/ -{file_include_pragma_beg} BEGIN(include_filename); - -{file_include_pragma_filename} { - /* got the include file name */ - int i; - - if (include_stack_ptr >= MAX_INCLUDE_DEPTH) { - fprintf(stderr, "Includes nested too deeply\n"); - exit( 1 ); - } - include_stack[include_stack_ptr].buffer_state = YY_CURRENT_BUFFER; - include_stack[include_stack_ptr].env = current_tracking; - include_stack[include_stack_ptr].filename = current_filename; - - for (i = 0, yyin = NULL; (INCLUDE_DIRECTORIES[i] != NULL) && (yyin == NULL); i++) { - char *full_name = strdup3(INCLUDE_DIRECTORIES[i], "/", yytext); - if (full_name == NULL) { - fprintf(stderr, "Out of memory!\n"); - exit( 1 ); - } - yyin = fopen(full_name, "r"); - free(full_name); - } - - if (!yyin) { - fprintf(stderr, "Error opening included file %s\n", yytext); - exit( 1 ); - } - - current_filename = strdup(yytext); - current_tracking = GetNewTracking(yyin); - include_stack_ptr++; - - /* switch input buffer to new file... */ - yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); - /* switch to whatever state was active before the include file */ - yy_pop_state(); - /* now process the new file... */ - } - - -<> { /* NOTE: We must not change the value of include_stack_ptr - * just yet. We must only decrement it if we are NOT - * at the end of the main file. - * If we have finished parsing the main file, then we - * must leave include_stack_ptr at 0, in case the - * parser is called once again with a new file. - * (In fact, we currently do just that!) - */ - free(current_tracking); - if (include_stack_ptr == 0) { - /* yyterminate() terminates the scanner and returns a 0 to the - * scanner's caller, indicating "all done". - * - * Our syntax parser (written with bison) has the token - * END_OF_INPUT associated to the value 0, so even though - * we don't explicitly return the token END_OF_INPUT - * calling yyterminate() is equivalent to doing that. - */ - yyterminate(); - } - else { - --include_stack_ptr; - yy_delete_buffer(YY_CURRENT_BUFFER); - yy_switch_to_buffer((include_stack[include_stack_ptr]).buffer_state); - current_tracking = include_stack[include_stack_ptr].env; - /* removing constness of char *. This is safe actually, - * since the only real const char * that is stored on the stack is - * the first one (i.e. the one that gets stored in include_stack[0], - * which is never free'd! - */ - /* NOTE: We do __NOT__ free the malloc()'d memory since - * pointers to this filename will be kept by many objects - * in the abstract syntax tree. - * This will later be used to provide correct error - * messages during semantic analysis (stage 3) - */ - /* free((char *)current_filename); */ - current_filename = include_stack[include_stack_ptr].filename; - yy_push_state(include_end); - } - } - -{file_include_pragma_end} yy_pop_state(); - - - /*********************************/ - /* Handle all the state changes! */ - /*********************************/ - - /* INITIAL -> decl_state */ -{ - /* NOTE: how about functions that do not declare variables, and go directly to the body_state??? - * - According to Section 2.5.1.3 (Function Declaration), item 2 in the list, a FUNCTION - * must have at least one input argument, so a correct declaration will have at least - * one VAR_INPUT ... VAR_END construct! - * - According to Section 2.5.2.2 (Function Block Declaration), a FUNCTION_BLOCK - * must have at least one input argument, so a correct declaration will have at least - * one VAR_INPUT ... VAR_END construct! - * - According to Section 2.5.3 (Programs), a PROGRAM must have at least one input - * argument, so a correct declaration will have at least one VAR_INPUT ... VAR_END - * construct! - * - * All the above means that we needn't worry about PROGRAMs, FUNCTIONs or - * FUNCTION_BLOCKs that do not have at least one VAR_END before the body_state. - * If the code has an error, and no VAR_END before the body, we will simply - * continue in the state, untill the end of the FUNCTION, FUNCTION_BLOCK - * or PROGAM. - */ -FUNCTION BEGIN(decl_state); return FUNCTION; -FUNCTION_BLOCK BEGIN(decl_state); return FUNCTION_BLOCK; -PROGRAM BEGIN(decl_state); return PROGRAM; -CONFIGURATION BEGIN(config_state); return CONFIGURATION; -} - - /* INITIAL -> body_state */ - /* required if the function, program, etc.. has no VAR block! */ - /* We comment it out since the standard does not allow this. */ - /* NOTE: Even if we were to include the following code, it */ - /* would have no effect whatsoever since the above */ - /* rules will take precendence! */ - /* -{ -FUNCTION BEGIN(body_state); return FUNCTION; -FUNCTION_BLOCK BEGIN(body_state); return FUNCTION_BLOCK; -PROGRAM BEGIN(body_state); return PROGRAM; -} - */ - - /* decl_state -> (body_state | sfc_state) */ -{ -END_VAR{st_whitespace}VAR {unput_text(strlen("END_VAR")); - return END_VAR; - } -END_VAR{st_whitespace}INITIAL_STEP {unput_text(strlen("END_VAR")); - yy_push_state(sfc_state); - return END_VAR; - } -END_VAR{st_whitespace} {unput_text(strlen("END_VAR")); - cmd_goto_body_state(); - return END_VAR; - } -} - - /* body_state -> (il_state | st_state) */ -{ -{st_whitespace_no_pragma} /* Eat any whitespace */ -{qualified_identifier}{st_whitespace}":=" unput_text(0); BEGIN(st_state); -{direct_variable_standard}{st_whitespace}":=" unput_text(0); BEGIN(st_state); -{qualified_identifier}"[" unput_text(0); BEGIN(st_state); - -RETURN unput_text(0); BEGIN(st_state); -IF unput_text(0); BEGIN(st_state); -CASE unput_text(0); BEGIN(st_state); -FOR unput_text(0); BEGIN(st_state); -WHILE unput_text(0); BEGIN(st_state); -REPEAT unput_text(0); BEGIN(st_state); -EXIT unput_text(0); BEGIN(st_state); - - /* ':=' occurs only in transitions, and not Function or FB bodies! */ -:= unput_text(0); BEGIN(st_state); - - /* Hopefully, the above rules (along with the last one), - * used to distinguish ST from IL, are - * enough to handle all ocurrences. However, if - * there is some situation where the compiler is getting confused, - * we add the following rule to detect 'label:' in IL code. This will - * allow the user to insert a label right at the beginning (which - * will probably not be used further by his code) simply as a way - * to force the compiler to interpret his code as IL code. - */ -{identifier}{st_whitespace}":"{st_whitespace} unput_text(0); BEGIN(il_state); - -{identifier} {int token = get_identifier_token(yytext); - if (token == prev_declared_fb_name_token) { - /* the code has a call to a function block */ - /* NOTE: if we ever decide to allow the user to use IL operator tokens - * (LD, ST, ...) as identifiers for variable names (including - * function block instances), then the above inference/conclusion - * may be incorrect, and this condition may have to be changed! - */ - BEGIN(st_state); - } else { - BEGIN(il_state); - } - unput_text(0); - } - -. unput_text(0); BEGIN(il_state); -} /* end of body_state lexical parser */ - - /* (il_state | st_state) -> $previous_state (decl_state or sfc_state) */ -{ -END_FUNCTION yy_pop_state(); unput_text(0); -END_FUNCTION_BLOCK yy_pop_state(); unput_text(0); -END_PROGRAM yy_pop_state(); unput_text(0); -END_TRANSITION yy_pop_state(); unput_text(0); -END_ACTION yy_pop_state(); unput_text(0); -} - - /* sfc_state -> INITIAL */ -{ -END_FUNCTION yy_pop_state(); unput_text(0); -END_FUNCTION_BLOCK yy_pop_state(); unput_text(0); -END_PROGRAM yy_pop_state(); unput_text(0); -} - - /* decl_state -> INITIAL */ -{ -END_FUNCTION BEGIN(INITIAL); return END_FUNCTION; -END_FUNCTION_BLOCK BEGIN(INITIAL); return END_FUNCTION_BLOCK; -END_PROGRAM BEGIN(INITIAL); return END_PROGRAM; -} - /* config -> INITIAL */ -END_CONFIGURATION BEGIN(INITIAL); return END_CONFIGURATION; - - - - /***************************************/ - /* Next is to to remove all whitespace */ - /***************************************/ - /* NOTE: pragmas are handled right at the beginning... */ - -{st_whitespace_no_pragma} /* Eat any whitespace */ -{il_whitespace_no_pragma} /* Eat any whitespace */ - - - - /*****************************************/ - /* B.1.1 Letters, digits and identifiers */ - /*****************************************/ - /* NOTE: 'R1', 'IN', etc... are IL operators, and therefore tokens - * On the other hand, the spec does not define them as keywords, - * which means they may be re-used for variable names, etc...! - * The syntax parser already caters for the possibility of these - * tokens being used for variable names in their declarations. - * When they are declared, they will be added to the variable symbol table! - * Further appearances of these tokens must no longer be parsed - * as R1_tokens etc..., but rather as variable_name_tokens! - * - * That is why the first thing we do with identifiers, even before - * checking whether they may be a 'keyword', is to check whether - * they have been previously declared as a variable name, - * - * However, we have a dilema! Should we here also check for - * prev_declared_derived_function_name_token? - * If we do, then the 'MOD' default library function (defined in - * the standard) will always be returned as a function name, and - * it will therefore not be possible to use it as an operator as - * in the following ST expression 'X := Y MOD Z;' ! - * If we don't, then even it will not be possible to use 'MOD' - * as a funtion as in 'X := MOD(Y, Z);' - * We solve this by NOT testing for function names here, and - * handling this function and keyword clash in bison! - */ - /* -{identifier} {int token = get_identifier_token(yytext); - // fprintf(stderr, "flex: analysing identifier '%s'...", yytext); - if ((token == prev_declared_variable_name_token) || -// (token == prev_declared_derived_function_name_token) || // DO NOT add this condition! - (token == prev_declared_fb_name_token)) { - // if (token != identifier_token) - // * NOTE: if we replace the above uncommented conditions with - * the simple test of (token != identifier_token), then - * 'MOD' et al must be removed from the - * library_symbol_table as a default function name! - * // - yylval.ID=strdup(yytext); - // fprintf(stderr, "returning token %d\n", token); - return token; - } - // otherwise, leave it for the other lexical parser rules... - // fprintf(stderr, "rejecting\n"); - REJECT; - } - */ - - /******************************************************/ - /******************************************************/ - /******************************************************/ - /***** *****/ - /***** *****/ - /***** N O W D O T H E K E Y W O R D S *****/ - /***** *****/ - /***** *****/ - /******************************************************/ - /******************************************************/ - /******************************************************/ - - -EN return EN; /* Keyword */ -ENO return ENO; /* Keyword */ - - - /******************************/ - /* B 1.2.1 - Numeric Literals */ - /******************************/ -TRUE return TRUE; /* Keyword */ -BOOL#1 return boolean_true_literal_token; -BOOL#TRUE return boolean_true_literal_token; -SAFEBOOL#1 {if (get_opt_safe_extensions()) {return safeboolean_true_literal_token;} else{REJECT;}} /* Keyword (Data Type) */ -SAFEBOOL#TRUE {if (get_opt_safe_extensions()) {return safeboolean_true_literal_token;} else{REJECT;}} /* Keyword (Data Type) */ - -FALSE return FALSE; /* Keyword */ -BOOL#0 return boolean_false_literal_token; -BOOL#FALSE return boolean_false_literal_token; -SAFEBOOL#0 {if (get_opt_safe_extensions()) {return safeboolean_false_literal_token;} else{REJECT;}} /* Keyword (Data Type) */ -SAFEBOOL#FALSE {if (get_opt_safe_extensions()) {return safeboolean_false_literal_token;} else{REJECT;}} /* Keyword (Data Type) */ - - - /************************/ - /* B 1.2.3.1 - Duration */ - /************************/ -t# return T_SHARP; /* Delimiter */ -T# return T_SHARP; /* Delimiter */ -TIME return TIME; /* Keyword (Data Type) */ - - - /************************************/ - /* B 1.2.3.2 - Time of day and Date */ - /************************************/ -TIME_OF_DAY return TIME_OF_DAY; /* Keyword (Data Type) */ -TOD return TIME_OF_DAY; /* Keyword (Data Type) */ -DATE return DATE; /* Keyword (Data Type) */ -d# return D_SHARP; /* Delimiter */ -D# return D_SHARP; /* Delimiter */ -DATE_AND_TIME return DATE_AND_TIME; /* Keyword (Data Type) */ -DT return DATE_AND_TIME; /* Keyword (Data Type) */ - - - /***********************************/ - /* B 1.3.1 - Elementary Data Types */ - /***********************************/ -BOOL return BOOL; /* Keyword (Data Type) */ - -BYTE return BYTE; /* Keyword (Data Type) */ -WORD return WORD; /* Keyword (Data Type) */ -DWORD return DWORD; /* Keyword (Data Type) */ -LWORD return LWORD; /* Keyword (Data Type) */ - -SINT return SINT; /* Keyword (Data Type) */ -INT return INT; /* Keyword (Data Type) */ -DINT return DINT; /* Keyword (Data Type) */ -LINT return LINT; /* Keyword (Data Type) */ - -USINT return USINT; /* Keyword (Data Type) */ -UINT return UINT; /* Keyword (Data Type) */ -UDINT return UDINT; /* Keyword (Data Type) */ -ULINT return ULINT; /* Keyword (Data Type) */ - -REAL return REAL; /* Keyword (Data Type) */ -LREAL return LREAL; /* Keyword (Data Type) */ - -WSTRING return WSTRING; /* Keyword (Data Type) */ -STRING return STRING; /* Keyword (Data Type) */ - -TIME return TIME; /* Keyword (Data Type) */ -DATE return DATE; /* Keyword (Data Type) */ -DT return DT; /* Keyword (Data Type) */ -TOD return TOD; /* Keyword (Data Type) */ -DATE_AND_TIME return DATE_AND_TIME; /* Keyword (Data Type) */ -TIME_OF_DAY return TIME_OF_DAY; /* Keyword (Data Type) */ - - /*****************************************************************/ - /* Keywords defined in "Safety Software Technical Specification" */ - /*****************************************************************/ - /* - * NOTE: The following keywords are define in - * "Safety Software Technical Specification, - * Part 1: Concepts and Function Blocks, - * Version 1.0 – Official Release" - * written by PLCopen - Technical Committee 5 - * - * We only support these extensions and keywords - * if the apropriate command line option is given. - */ -SAFEBOOL {if (get_opt_safe_extensions()) {return SAFEBOOL;} else {REJECT;}} - -SAFEBYTE {if (get_opt_safe_extensions()) {return SAFEBYTE;} else {REJECT;}} -SAFEWORD {if (get_opt_safe_extensions()) {return SAFEWORD;} else {REJECT;}} -SAFEDWORD {if (get_opt_safe_extensions()) {return SAFEDWORD;} else{REJECT;}} -SAFELWORD {if (get_opt_safe_extensions()) {return SAFELWORD;} else{REJECT;}} - -SAFEREAL {if (get_opt_safe_extensions()) {return SAFESINT;} else{REJECT;}} -SAFELREAL {if (get_opt_safe_extensions()) {return SAFELREAL;} else{REJECT;}} - -SAFESINT {if (get_opt_safe_extensions()) {return SAFESINT;} else{REJECT;}} -SAFEINT {if (get_opt_safe_extensions()) {return SAFEINT;} else{REJECT;}} -SAFEDINT {if (get_opt_safe_extensions()) {return SAFEDINT;} else{REJECT;}} -SAFELINT {if (get_opt_safe_extensions()) {return SAFELINT;} else{REJECT;}} - -SAFEUSINT {if (get_opt_safe_extensions()) {return SAFEUSINT;} else{REJECT;}} -SAFEUINT {if (get_opt_safe_extensions()) {return SAFEUINT;} else{REJECT;}} -SAFEUDINT {if (get_opt_safe_extensions()) {return SAFEUDINT;} else{REJECT;}} -SAFEULINT {if (get_opt_safe_extensions()) {return SAFEULINT;} else{REJECT;}} - - /* SAFESTRING and SAFEWSTRING are not yet supported, i.e. checked correctly, in the semantic analyser (stage 3) */ - /* so it is best not to support them at all... */ - /* -SAFEWSTRING {if (get_opt_safe_extensions()) {return SAFEWSTRING;} else{REJECT;}} -SAFESTRING {if (get_opt_safe_extensions()) {return SAFESTRING;} else{REJECT;}} - */ - -SAFETIME {if (get_opt_safe_extensions()) {return SAFETIME;} else{REJECT;}} -SAFEDATE {if (get_opt_safe_extensions()) {return SAFEDATE;} else{REJECT;}} -SAFEDT {if (get_opt_safe_extensions()) {return SAFEDT;} else{REJECT;}} -SAFETOD {if (get_opt_safe_extensions()) {return SAFETOD;} else{REJECT;}} -SAFEDATE_AND_TIME {if (get_opt_safe_extensions()) {return SAFEDATE_AND_TIME;} else{REJECT;}} -SAFETIME_OF_DAY {if (get_opt_safe_extensions()) {return SAFETIME_OF_DAY;} else{REJECT;}} - - /********************************/ - /* B 1.3.2 - Generic data types */ - /********************************/ - /* Strangely, the following symbols do not seem to be required! */ - /* But we include them so they become reserved words, and do not - * get passed up to bison as an identifier... - */ -ANY return ANY; /* Keyword (Data Type) */ -ANY_DERIVED return ANY_DERIVED; /* Keyword (Data Type) */ -ANY_ELEMENTARY return ANY_ELEMENTARY; /* Keyword (Data Type) */ -ANY_MAGNITUDE return ANY_MAGNITUDE; /* Keyword (Data Type) */ -ANY_NUM return ANY_NUM; /* Keyword (Data Type) */ -ANY_REAL return ANY_REAL; /* Keyword (Data Type) */ -ANY_INT return ANY_INT; /* Keyword (Data Type) */ -ANY_BIT return ANY_BIT; /* Keyword (Data Type) */ -ANY_STRING return ANY_STRING; /* Keyword (Data Type) */ -ANY_DATE return ANY_DATE; /* Keyword (Data Type) */ - - - /********************************/ - /* B 1.3.3 - Derived data types */ - /********************************/ -":=" return ASSIGN; /* Delimiter */ -".." return DOTDOT; /* Delimiter */ -TYPE return TYPE; /* Keyword */ -END_TYPE return END_TYPE; /* Keyword */ -ARRAY return ARRAY; /* Keyword */ -OF return OF; /* Keyword */ -STRUCT return STRUCT; /* Keyword */ -END_STRUCT return END_STRUCT; /* Keyword */ - - - /*********************/ - /* B 1.4 - Variables */ - /*********************/ - - /******************************************/ - /* B 1.4.3 - Declaration & Initialisation */ - /******************************************/ -VAR_INPUT return VAR_INPUT; /* Keyword */ -VAR_OUTPUT return VAR_OUTPUT; /* Keyword */ -VAR_IN_OUT return VAR_IN_OUT; /* Keyword */ -VAR_EXTERNAL return VAR_EXTERNAL; /* Keyword */ -VAR_GLOBAL return VAR_GLOBAL; /* Keyword */ -END_VAR return END_VAR; /* Keyword */ -RETAIN return RETAIN; /* Keyword */ -NON_RETAIN return NON_RETAIN; /* Keyword */ -R_EDGE return R_EDGE; /* Keyword */ -F_EDGE return F_EDGE; /* Keyword */ -AT return AT; /* Keyword */ - - - /***********************/ - /* B 1.5.1 - Functions */ - /***********************/ -FUNCTION return FUNCTION; /* Keyword */ -END_FUNCTION return END_FUNCTION; /* Keyword */ -VAR return VAR; /* Keyword */ -CONSTANT return CONSTANT; /* Keyword */ - - - /*****************************/ - /* B 1.5.2 - Function Blocks */ - /*****************************/ -FUNCTION_BLOCK return FUNCTION_BLOCK; /* Keyword */ -END_FUNCTION_BLOCK return END_FUNCTION_BLOCK; /* Keyword */ -VAR_TEMP return VAR_TEMP; /* Keyword */ -VAR return VAR; /* Keyword */ -NON_RETAIN return NON_RETAIN; /* Keyword */ -END_VAR return END_VAR; /* Keyword */ - - - /**********************/ - /* B 1.5.3 - Programs */ - /**********************/ -PROGRAM return PROGRAM; /* Keyword */ -END_PROGRAM return END_PROGRAM; /* Keyword */ - - - /********************************************/ - /* B 1.6 Sequential Function Chart elements */ - /********************************************/ - /* NOTE: the following identifiers/tokens clash with the R and S IL operators, as well - .* as other identifiers that may be used as variable names inside IL and ST programs. - * They will have to be handled when we include parsing of SFC... For now, simply - * ignore them! - */ - -ACTION return ACTION; /* Keyword */ -END_ACTION return END_ACTION; /* Keyword */ - -TRANSITION return TRANSITION; /* Keyword */ -END_TRANSITION return END_TRANSITION; /* Keyword */ -FROM return FROM; /* Keyword */ -TO return TO; /* Keyword */ - -INITIAL_STEP return INITIAL_STEP; /* Keyword */ -STEP return STEP; /* Keyword */ -END_STEP return END_STEP; /* Keyword */ - - /* PRIORITY is not a keyword, so we only return it when - * it is explicitly required and we are not expecting any identifiers - * that could also use the same letter sequence (i.e. an identifier: piority) - */ -PRIORITY return PRIORITY; - -{ -L return L; -D return D; -SD return SD; -DS return DS; -SL return SL; -N return N; -P return P; -R return R; -S return S; -} - - - /********************************/ - /* B 1.7 Configuration elements */ - /********************************/ -CONFIGURATION return CONFIGURATION; /* Keyword */ -END_CONFIGURATION return END_CONFIGURATION; /* Keyword */ -TASK return TASK; /* Keyword */ -RESOURCE return RESOURCE; /* Keyword */ -ON return ON; /* Keyword */ -END_RESOURCE return END_RESOURCE; /* Keyword */ -VAR_CONFIG return VAR_CONFIG; /* Keyword */ -VAR_ACCESS return VAR_ACCESS; /* Keyword */ -END_VAR return END_VAR; /* Keyword */ -WITH return WITH; /* Keyword */ -PROGRAM return PROGRAM; /* Keyword */ -RETAIN return RETAIN; /* Keyword */ -NON_RETAIN return NON_RETAIN; /* Keyword */ -READ_WRITE return READ_WRITE; /* Keyword */ -READ_ONLY return READ_ONLY; /* Keyword */ - - /* PRIORITY, SINGLE and INTERVAL are not a keywords, so we only return them when - * it is explicitly required and we are not expecting any identifiers - * that could also use the same letter sequence (i.e. an identifier: piority, ...) - */ -{ -PRIORITY return PRIORITY; -SINGLE return SINGLE; -INTERVAL return INTERVAL; -} - - /***********************************/ - /* B 2.1 Instructions and Operands */ - /***********************************/ -\n return EOL; - - - /*******************/ - /* B 2.2 Operators */ - /*******************/ - /* NOTE: we can't have flex return the same token for - * ANDN and &N, neither for AND and &, since - * AND and ANDN are considered valid variable - * function or functionblock type names! - * This means that the parser may decide that the - * AND or ANDN strings found in the source code - * are being used as variable names - * and not as operators, and will therefore transform - * these tokens into indentifier tokens! - * We can't have the parser thinking that the source - * code contained the string AND (which may be interpreted - * as a vairable name) when in reality the source code - * merely contained the character &, so we use two - * different tokens for & and AND (and similarly - * ANDN and &N)! - */ - /* The following tokens clash with ST expression operators and Standard Functions */ - /* They are also keywords! */ -AND return AND; /* Keyword */ -MOD return MOD; /* Keyword */ -OR return OR; /* Keyword */ -XOR return XOR; /* Keyword */ -NOT return NOT; /* Keyword */ - - /* The following tokens clash with Standard Functions */ - /* They are keywords because they are a function name */ -{ -ADD return ADD; /* Keyword (Standard Function) */ -DIV return DIV; /* Keyword (Standard Function) */ -EQ return EQ; /* Keyword (Standard Function) */ -GE return GE; /* Keyword (Standard Function) */ -GT return GT; /* Keyword (Standard Function) */ -LE return LE; /* Keyword (Standard Function) */ -LT return LT; /* Keyword (Standard Function) */ -MUL return MUL; /* Keyword (Standard Function) */ -NE return NE; /* Keyword (Standard Function) */ -SUB return SUB; /* Keyword (Standard Function) */ -} - - /* The following tokens clash with SFC action qualifiers */ - /* They are not keywords! */ -{ -S return S; -R return R; -} - - /* The following tokens clash with ST expression operators */ -& return AND2; /* NOT a Delimiter! */ - - /* The following tokens have no clashes */ - /* They are not keywords! */ -{ -LD return LD; -LDN return LDN; -ST return ST; -STN return STN; -S1 return S1; -R1 return R1; -CLK return CLK; -CU return CU; -CD return CD; -PV return PV; -IN return IN; -PT return PT; -ANDN return ANDN; -&N return ANDN2; -ORN return ORN; -XORN return XORN; -CAL return CAL; -CALC return CALC; -CALCN return CALCN; -RET return RET; -RETC return RETC; -RETCN return RETCN; -JMP return JMP; -JMPC return JMPC; -JMPCN return JMPCN; -} - - /***********************/ - /* B 3.1 - Expressions */ - /***********************/ -"**" return OPER_EXP; /* NOT a Delimiter! */ -"<>" return OPER_NE; /* NOT a Delimiter! */ -">=" return OPER_GE; /* NOT a Delimiter! */ -"<=" return OPER_LE; /* NOT a Delimiter! */ -& return AND2; /* NOT a Delimiter! */ -AND return AND; /* Keyword */ -XOR return XOR; /* Keyword */ -OR return OR; /* Keyword */ -NOT return NOT; /* Keyword */ -MOD return MOD; /* Keyword */ - - - /*****************************************/ - /* B 3.2.2 Subprogram Control Statements */ - /*****************************************/ -:= return ASSIGN; /* Delimiter */ -=> return SENDTO; /* Delimiter */ -RETURN return RETURN; /* Keyword */ - - - /********************************/ - /* B 3.2.3 Selection Statements */ - /********************************/ -IF return IF; /* Keyword */ -THEN return THEN; /* Keyword */ -ELSIF return ELSIF; /* Keyword */ -ELSE return ELSE; /* Keyword */ -END_IF return END_IF; /* Keyword */ - -CASE return CASE; /* Keyword */ -OF return OF; /* Keyword */ -ELSE return ELSE; /* Keyword */ -END_CASE return END_CASE; /* Keyword */ - - - /********************************/ - /* B 3.2.4 Iteration Statements */ - /********************************/ -FOR return FOR; /* Keyword */ -TO return TO; /* Keyword */ -BY return BY; /* Keyword */ -DO return DO; /* Keyword */ -END_FOR return END_FOR; /* Keyword */ - -WHILE return WHILE; /* Keyword */ -DO return DO; /* Keyword */ -END_WHILE return END_WHILE; /* Keyword */ - -REPEAT return REPEAT; /* Keyword */ -UNTIL return UNTIL; /* Keyword */ -END_REPEAT return END_REPEAT; /* Keyword */ - -EXIT return EXIT; /* Keyword */ - - - - - - - /********************************************************/ - /********************************************************/ - /********************************************************/ - /***** *****/ - /***** *****/ - /***** N O W W O R K W I T H V A L U E S *****/ - /***** *****/ - /***** *****/ - /********************************************************/ - /********************************************************/ - /********************************************************/ - - - /********************************************/ - /* B.1.4.1 Directly Represented Variables */ - /********************************************/ -{direct_variable} {yylval.ID=strdup(yytext); return get_direct_variable_token(yytext);} - - - /******************************************/ - /* B 1.4.3 - Declaration & Initialisation */ - /******************************************/ -{incompl_location} {yylval.ID=strdup(yytext); return incompl_location_token;} - - - /************************/ - /* B 1.2.3.1 - Duration */ - /************************/ -{fixed_point} {yylval.ID=strdup(yytext); return fixed_point_token;} - -{fixed_point_d} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_d_token;} -{integer_d} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_d_token;} - -{fixed_point_h} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_h_token;} -{integer_h} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_h_token;} - -{fixed_point_m} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_m_token;} -{integer_m} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_m_token;} - -{fixed_point_s} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_s_token;} -{integer_s} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_s_token;} - -{fixed_point_ms} {yylval.ID=strdup(yytext); yylval.ID[yyleng-2] = '\0'; return fixed_point_ms_token;} -{integer_ms} {yylval.ID=strdup(yytext); yylval.ID[yyleng-2] = '\0'; return integer_ms_token;} - - - /*******************************/ - /* B.1.2.2 Character Strings */ - /*******************************/ -{double_byte_character_string} {yylval.ID=strdup(yytext); return double_byte_character_string_token;} -{single_byte_character_string} {yylval.ID=strdup(yytext); return single_byte_character_string_token;} - - - /******************************/ - /* B.1.2.1 Numeric literals */ - /******************************/ -{integer} {yylval.ID=strdup(yytext); return integer_token;} -{real} {yylval.ID=strdup(yytext); return real_token;} -{binary_integer} {yylval.ID=strdup(yytext); return binary_integer_token;} -{octal_integer} {yylval.ID=strdup(yytext); return octal_integer_token;} -{hex_integer} {yylval.ID=strdup(yytext); return hex_integer_token;} - - - /*****************************************/ - /* B.1.1 Letters, digits and identifiers */ - /*****************************************/ -{identifier}/({st_whitespace})"=>" {yylval.ID=strdup(yytext); return sendto_identifier_token;} -{identifier}/({il_whitespace})"=>" {yylval.ID=strdup(yytext); return sendto_identifier_token;} -{identifier} {yylval.ID=strdup(yytext); - // printf("returning identifier...: %s, %d\n", yytext, get_identifier_token(yytext)); - return get_identifier_token(yytext);} - - - - - - - /************************************************/ - /************************************************/ - /************************************************/ - /***** *****/ - /***** *****/ - /***** T H E L E F T O V E R S . . . *****/ - /***** *****/ - /***** *****/ - /************************************************/ - /************************************************/ - /************************************************/ - - /* do the single character tokens... - * - * e.g.: ':' '(' ')' '+' '*' ... - */ -. {return yytext[0];} - - -%% - - -/***********************************/ -/* Utility function definitions... */ -/***********************************/ - -/* print the include file stack to stderr... */ -void print_include_stack(void) { - int i; - - if ((include_stack_ptr - 1) >= 0) - fprintf (stderr, "in file "); - for (i = include_stack_ptr - 1; i >= 0; i--) - fprintf (stderr, "included from file %s:%d\n", include_stack[i].filename, include_stack[i].env->lineNumber); -} - - -/* return all the text in the current token back to the input stream, except the first n chars. */ -void unput_text(unsigned int n) { - /* it seems that flex has a bug in that it will not correctly count the line numbers - * if we return newlines back to the input stream. These newlines will be re-counted - * a second time when they are processed again by flex. - * We therefore determine how many newlines are in the text we are returning, - * and decrement the line counter acordingly... - */ - /*unsigned int i; - - for (i = n; i < strlen(yytext); i++) - if (yytext[i] == '\n') - current_tracking->lineNumber--;*/ - - /* now return all the text back to the input stream... */ - yyless(n); -} - - -/* Called by flex when it reaches the end-of-file */ -int yywrap(void) -{ - /* We reached the end of the input file... */ - - /* Should we continue with another file? */ - /* If so: - * open the new file... - * return 0; - */ - - /* to we stop processing... - * - * return 1; - */ - - - return 1; /* Stop scanning at end of input file. */ -} - - - -/*************************************/ -/* Include a main() function to test */ -/* the token parsing by flex.... */ -/*************************************/ -#ifdef TEST_MAIN - -#include "../util/symtable.hh" - -yystype yylval; -YYLTYPE yylloc; - -const char *current_filename; - - - -int get_identifier_token(const char *identifier_str) {return 0;} -int get_direct_variable_token(const char *direct_variable_str) {return 0;} - - -int main(int argc, char **argv) { - - FILE *in_file; - int res; - - if (argc == 1) { - /* Work as an interactive (command line) parser... */ - while((res=yylex())) - fprintf(stderr, "(line %d)token: %d\n", yylineno, res); - } else { - /* Work as non-interactive (file) parser... */ - if((in_file = fopen(argv[1], "r")) == NULL) { - char *errmsg = strdup2("Error opening main file ", argv[1]); - perror(errmsg); - free(errmsg); - return -1; - } - - /* parse the file... */ - yyin = in_file; - current_filename = argv[1]; - while(1) { - res=yylex(); - fprintf(stderr, "(line %d)token: %d (%s)\n", yylineno, res, yylval.ID); - } - } - - return 0; - -} -#endif diff -r 17bffb57a8c5 -r 0f24db96b519 stage1_2/iec.y --- a/stage1_2/iec.y Fri Jul 29 16:08:40 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8307 +0,0 @@ -/* - * matiec - a compiler for the programming languages defined in IEC 61131-3 - * - * Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt) - * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant - * - * 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 . - * - * - * This code is made available on the understanding that it will not be - * used in safety-critical situations without a full and competent review. - */ - -/* - * An IEC 61131-3 compiler. - * - * Based on the - * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) - * - */ - -/* - * Stage 2 - * ======= - * - * This file contains the syntax definition of the textual - * languages IL and ST, as well as the textual version of SFC. - * The syntax parser, comprising the 2nd stage of the overall - * compiler, is generated by runing bison on this file. - */ - - - - -/**********************************************************************/ -/**********************************************************************/ -/**********************************************************************/ -/**********************************************************************/ -/******* *******/ -/******* The following syntax does not have any conflicts. *******/ -/******* *******/ -/******* P L E A S E K E E P I T T H A T W A Y ! *******/ -/******* =================================================== *******/ -/******* *******/ -/**********************************************************************/ -/**********************************************************************/ -/**********************************************************************/ -/**********************************************************************/ - - - - -%{ -#include /* required for strdup() */ - - -/* declare the token parser generated by flex... */ -int yylex(void); - -/* declare the error handler defined at the end of this file */ -void yyerror (const char *error_msg); - -/* produce a more verbose parsing error message */ -#define YYERROR_VERBOSE - -/* Include debuging code. - * Printing of debug info must then be activated by setting - * the variable yydebug to 1. - */ -#define YYDEBUG 0 - - -/* file with declaration of absyntax classes... */ -#include "../absyntax/absyntax.hh" - -/* file with declaration of token constants. Generated by bison! */ -#include "iec.y.hh" - -/* The interface through which bison and flex interact. */ -#include "stage1_2_priv.hh" - - -#include "../absyntax_utils/add_en_eno_param_decl.hh" /* required for add_en_eno_param_decl_c */ - -/* an ugly hack!! - * We will probably not need it when we decide - * to cut down the abstract syntax down to size. - * We keep it as it is until we get to write - * stages 3 and 4 of the compiler. Who knows, - * we might just find out that we really do need - * the abstract syntax tree to stay as it is - * afterall! - */ -/* for each element in list_c * - * execute the code - */ -#define FOR_EACH_ELEMENT(elem, list, code) { \ - symbol_c *elem; \ - for(int i = 0; i < list->n; i++) { \ - elem = list->elements[i]; \ - code; \ - } \ -} - - - -/* Macros used to pass the line and column locations when - * creating a new object for the abstract syntax tree. - */ -#define locloc(foo) foo.first_line, foo.first_column, foo.first_file, foo.first_order, foo.last_line, foo.last_column, foo.last_file, foo.last_order -#define locf(foo) foo.first_line, foo.first_column, foo.first_file, foo.first_order -#define locl(foo) foo.last_line, foo.last_column, foo.last_file, foo.last_order - -/* Redefine the default action to take for each rule, so that the filenames are correctly processed... */ -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (N) \ - { \ - (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \ - (Current).first_file = YYRHSLOC(Rhs, 1).first_file; \ - (Current).first_order = YYRHSLOC(Rhs, 1).first_order; \ - (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC(Rhs, N).last_column; \ - (Current).last_file = YYRHSLOC(Rhs, 1).last_file; \ - (Current).last_order = YYRHSLOC(Rhs, 1).last_order; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC(Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC(Rhs, 0).last_column; \ - (Current).first_file = (Current).last_file = \ - YYRHSLOC(Rhs, 0).last_file; \ - (Current).first_order = (Current).last_order = \ - YYRHSLOC(Rhs, 0).last_order; \ - } \ - while (0) - - -/* A macro for printing out internal parser errors... */ -#define ERROR error_exit(__FILE__,__LINE__) -/* function defined in main.cc */ -extern void error_exit(const char *file_name, int line_no); - - - -/*************************/ -/* global variables... */ -/*************************/ -/* NOTE: For some strange reason bison ver 2.3 is including these declarations - * in the iec.y.hh file, which is in turn included by flex. - * We cannot therefore define any variables over here, but merely declare - * their existance (otherwise we get errors when linking the code, since we - * would get a new variable defined each time iec.y.hh is included!). - * Even though the variables are declared 'extern' over here, they will in - * fact be defined towards the end of this same file (i.e. in the prologue) - */ - - -/* NOTE: These variable are really parameters we would like the stage2__ function to pass - * to the yyparse() function. However, the yyparse() function is created automatically - * by bison, so we cannot add parameters to this function. The only other - * option is to use global variables! yuck! - */ - -/* A global flag used to tell the parser if overloaded funtions should be allowed. - * The IEC 61131-3 standard allows overloaded funtions in the standard library, - * but disallows them in user code... - */ -extern bool allow_function_overloading; - -/* A flag to tell the compiler whether to allow the declaration - * of extensible function (i.e. functions that may have a variable number of - * input parameters, such as AND(word#33, word#44, word#55, word#66). - * This is an extension to the standard syntax. - * See comments below for details why we support this! - */ -extern bool allow_extensible_function_parameters; - -/* A global flag used to tell the parser whether to include the full variable location - * when printing out error messages... - */ -extern bool full_token_loc; - -/* A pointer to the root of the parsing tree that will be generated - * by bison. - */ -extern symbol_c *tree_root; - - - -/************************/ -/* forward declarations */ -/************************/ -/* The functions declared here are defined at the end of this file... */ - -/* Convert an il_operator_c into an identifier_c */ -symbol_c *il_operator_c_2_identifier_c(symbol_c *il_operator); - -/* return if current token is a syntax element */ -/* ERROR_CHECK_BEGIN */ -bool is_current_syntax_token(); -/* ERROR_CHECK_END */ - -/* print an error message */ -void print_err_msg(int first_line, - int first_column, - const char *first_filename, - long int first_order, - int last_line, - int last_column, - const char *last_filename, - long int last_order, - const char *additional_error_msg); -%} - - - - -// %glr-parser -// %expect-rr 1 - - -/* The following definitions need to be inside a '%code requires' - * so that they are also included in the header files. If this were not the case, - * YYLTYPE would be delcared as something in the iec.cc file, and another thing - * (actually the default value of YYLTYPE) in the iec.y.hh heder file. - */ -%code requires { -/* define a new data type to store the locations, so we can also store - * the filename in which the token is expressed. - */ -/* NOTE: since this code will be placed in the iec.y.hh header file, - * as well as the iec.cc file that also includes the iec.y.hh header file, - * declaring the typedef struct yyltype__local here would result in a - * compilation error when compiling iec.cc, as this struct would be - * declared twice. - * We therefore use the #if !defined YYLTYPE ... - * to make sure only the first declaration is parsed by the C++ compiler. - * - * At first glance it seems that what we really should do is delcare the - * YYLTYPE directly as an anonymous struct, thus: - * #define YYLTYPE struct{ ...} - * however, this also results in compilation errors. - * - * I (Mario) think this is kind of a hack. If you know how to - * do this re-declaration of YYLTYPE properly, please let me know! - */ -#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED - typedef struct { - int first_line; - int first_column; - const char *first_file; - long int first_order; - int last_line; - int last_column; - const char *last_file; - long int last_order; - } yyltype__local; - #define YYLTYPE yyltype__local -#endif -} - - - -%union { - symbol_c *leaf; - list_c *list; - char *ID; /* token value */ -} - -/* - TODO: DO we need to define a destructor do free - memory when recovering from errors, or do the - class destructors already handle this? - Following is example on how to define - detructors, using the syntax: - %destructor { CODE } SYMBOLS -%union - { - char *string; - } - %token STRING - %type string - %destructor { free ($$); } STRING string -*/ - - - - -/*************************************/ -/* Prelimenary helpful constructs... */ -/*************************************/ -/* A token used to identify the very end of the input file - * after all includes have already been processed. - * - * Flex automatically returns the token with value 0 - * at the end of the file. We therefore specify here - * a token with that exact same value here, so we can use it - * to detect the very end of the input files. - */ -%token END_OF_INPUT 0 - -/* A bogus token that, in principle, flex MUST NEVER generate */ -/* USE 1: - * ====== - * This token is currently also being used as the default - * initialisation value of the token_id member in - * the symbol_c base class. - * - * USE 2 - * ===== - * This token may also be used in the future to remove - * mysterious reduce/reduce conflicts due to the fact - * that our grammar may not be LALR(1) but merely LR(1). - * This means that bison cannot handle it without some - * caoxing from ourselves. We will then need this token - * to do the coaxing... - */ -%token BOGUS_TOKEN_ID - -%type start - -%type any_identifier - -%token prev_declared_variable_name_token -%token prev_declared_direct_variable_token -%token prev_declared_fb_name_token -%type prev_declared_variable_name -%type prev_declared_direct_variable -%type prev_declared_fb_name - -%token prev_declared_simple_type_name_token -%token prev_declared_subrange_type_name_token -%token prev_declared_enumerated_type_name_token -%token prev_declared_array_type_name_token -%token prev_declared_structure_type_name_token -%token prev_declared_string_type_name_token - -%type prev_declared_simple_type_name -%type prev_declared_subrange_type_name -%type prev_declared_enumerated_type_name -%type prev_declared_array_type_name -%type prev_declared_structure_type_name -%type prev_declared_string_type_name - -%token prev_declared_derived_function_name_token -%token prev_declared_derived_function_block_name_token -%token prev_declared_program_type_name_token -%type prev_declared_derived_function_name -%type prev_declared_derived_function_block_name -%type prev_declared_program_type_name - - - - -/**********************************************************************************/ -/* B XXX - Things that are missing from the standard, but should have been there! */ -/**********************************************************************************/ - -/* Pragmas that our compiler will accept. - * See the comment in iec.flex for why these pragmas exist. - */ -%token disable_code_generation_pragma_token -%token enable_code_generation_pragma_token -%type disable_code_generation_pragma -%type enable_code_generation_pragma - - -/* All other pragmas that we do not support... */ -/* In most stage 4, the text inside the pragmas will simply be copied to the output file. - * This allows us to insert C code (if using stage 4 generating C code) - * inside/interningled with the IEC 61131-3 code! - */ -%token pragma_token -%type pragma - -/* The joining of all previous pragmas, i.e. any possible pragma */ -%type any_pragma - - -/* Where do these tokens belong?? They are missing from the standard! */ -/* NOTE: There are other tokens related to these 'EN' ENO', that are also - * missing from the standard. However, their location in the annex B is - * relatively obvious, so they have been inserted in what seems to us their - * correct place in order to ease understanding of the parser... - * - * please read the comment above the definition of 'variable' in section B1.4 for details. - */ -%token EN -%token ENO -%type en_identifier -%type eno_identifier - - - - -/***************************/ -/* B 0 - Programming Model */ -/***************************/ -%type library -%type library_element_declaration - - -/*******************************************/ -/* B 1.1 - Letters, digits and identifiers */ -/*******************************************/ -/* Done totally within flex... - letter - digit - octal_digit - hex_digit -*/ -%token identifier_token -%type identifier - -/*********************/ -/* B 1.2 - Constants */ -/*********************/ -%type constant -%type non_negative_constant - -/******************************/ -/* B 1.2.1 - Numeric Literals */ -/******************************/ -/* Done totally within flex... - bit -*/ -%type numeric_literal -%type integer_literal -%type signed_integer -%token integer_token -%type integer -%token binary_integer_token -%type binary_integer -%token octal_integer_token -%type octal_integer -%token hex_integer_token -%type hex_integer -%token real_token -%type real -%type signed_real -%type real_literal -// %type exponent -%type bit_string_literal -%type boolean_literal - -%token safeboolean_true_literal_token -%token safeboolean_false_literal_token -%token boolean_true_literal_token -%token boolean_false_literal_token - -%token FALSE -%token TRUE - - -/*******************************/ -/* B 1.2.2 - Character Strings */ -/*******************************/ -%token single_byte_character_string_token -%token double_byte_character_string_token - -%type character_string -%type single_byte_character_string -%type double_byte_character_string - - -/***************************/ -/* B 1.2.3 - Time Literals */ -/***************************/ -%type time_literal - - -/************************/ -/* B 1.2.3.1 - Duration */ -/************************/ -%type duration -%type interval -%type days -%type fixed_point -%type hours -%type minutes -%type seconds -%type milliseconds - -%type integer_d -%type integer_h -%type integer_m -%type integer_s -%type integer_ms -%type fixed_point_d -%type fixed_point_h -%type fixed_point_m -%type fixed_point_s -%type fixed_point_ms - -%token fixed_point_token -%token fixed_point_d_token -%token integer_d_token -%token fixed_point_h_token -%token integer_h_token -%token fixed_point_m_token -%token integer_m_token -%token fixed_point_s_token -%token integer_s_token -%token fixed_point_ms_token -%token integer_ms_token - -// %token TIME -%token T_SHARP - - -/************************************/ -/* B 1.2.3.2 - Time of day and Date */ -/************************************/ -%type time_of_day -%type daytime -%type day_hour -%type day_minute -%type day_second -%type date -%type date_literal -%type year -%type month -%type day -%type date_and_time - -// %token TIME_OF_DAY -// %token DATE -%token D_SHARP -// %token DATE_AND_TIME - - -/**********************/ -/* B 1.3 - Data Types */ -/**********************/ -/* Strangely, the following symbol does seem to be required! */ -// %type data_type_name -%type non_generic_type_name - - -/***********************************/ -/* B 1.3.1 - Elementary Data Types */ -/***********************************/ -/* NOTES: - * - * - To make the definition of bit_string_literal more - * concise, it is useful to use an extra non-terminal - * symbol (i.e. a grouping or construct) that groups the - * following elements (BYTE, WORD, DWORD, LWORD). - * Note that the definition of bit_string_type_name - * (according to the spec) includes the above elements - * and an extra BOOL. - * We could use an extra construct with the first four - * elements to be used solely in the definition of - * bit_string_literal, but with the objective of not - * having to replicate the actions (if we ever need - * to change them, they would need to be changed in both - * bit_string_type_name and the extra grouping), we - * have re-defined bit_string_type_name as only including - * the first four elements. - * In order to have our parser implement the specification - * correctly we have augmented every occurence of - * bit_string_type_name in other rules with the BOOL - * token. Since bit_string_type_name only appears in - * the rule for elementary_type_name, this does not - * seem to be a big concession to make! - * - * - We have added a helper symbol to concentrate the - * instantiation of STRING and WSTRING into a single - * location (elementary_string_type_name). - * These two elements show up in several other rules, - * but we want to create the equivalent abstract syntax - * in a single location of this file, in order to make - * possible future changes easier to edit... - */ -%type elementary_type_name -%type numeric_type_name -%type integer_type_name -%type signed_integer_type_name -%type unsigned_integer_type_name -%type real_type_name -%type date_type_name -%type bit_string_type_name -/* helper symbol to concentrate the instantiation - * of STRING and WSTRING into a single location - */ -%type elementary_string_type_name - -%token BYTE -%token WORD -%token DWORD -%token LWORD - -%token LREAL -%token REAL - -%token SINT -%token INT -%token DINT -%token LINT - -%token USINT -%token UINT -%token UDINT -%token ULINT - -%token WSTRING -%token STRING -%token BOOL - -%token TIME -%token DATE -%token DATE_AND_TIME -%token DT -%token TIME_OF_DAY -%token TOD - -/******************************************************/ -/* Symbols defined in */ -/* "Safety Software Technical Specification, */ -/* Part 1: Concepts and Function Blocks, */ -/* Version 1.0 – Official Release" */ -/* by PLCopen - Technical Committee 5 - 2006-01-31 */ -/******************************************************/ - -%token SAFEBYTE -%token SAFEWORD -%token SAFEDWORD -%token SAFELWORD - -%token SAFELREAL -%token SAFEREAL - -%token SAFESINT -%token SAFEINT -%token SAFEDINT -%token SAFELINT - -%token SAFEUSINT -%token SAFEUINT -%token SAFEUDINT -%token SAFEULINT - -%token SAFEWSTRING -%token SAFESTRING -%token SAFEBOOL - -%token SAFETIME -%token SAFEDATE -%token SAFEDATE_AND_TIME -%token SAFEDT -%token SAFETIME_OF_DAY -%token SAFETOD - -/********************************/ -/* B 1.3.2 - Generic data types */ -/********************************/ -/* Strangely, the following symbol does seem to be required! */ -// %type generic_type_name - -/* The following tokens do not seem to be used either - * but we declare them so they become reserved words... - */ -%token ANY -%token ANY_DERIVED -%token ANY_ELEMENTARY -%token ANY_MAGNITUDE -%token ANY_NUM -%token ANY_REAL -%token ANY_INT -%token ANY_BIT -%token ANY_STRING -%token ANY_DATE - - -/********************************/ -/* B 1.3.3 - Derived data types */ -/********************************/ -%type derived_type_name -%type single_element_type_name -// %type simple_type_name -// %type subrange_type_name -// %type enumerated_type_name -// %type array_type_name -// %type structure_type_name - -%type data_type_declaration -/* helper symbol for data_type_declaration */ -%type type_declaration_list -%type type_declaration -%type single_element_type_declaration - -%type simple_type_declaration -%type simple_spec_init -%type simple_specification - -%type subrange_type_declaration -%type subrange_spec_init -%type subrange_specification -%type subrange - -%type enumerated_type_declaration -%type enumerated_spec_init -%type enumerated_specification -/* helper symbol for enumerated_value */ -%type enumerated_value_list -%type enumerated_value -//%type enumerated_value_without_identifier - -%type array_type_declaration -%type array_spec_init -%type array_specification -/* helper symbol for array_specification */ -%type array_subrange_list -%type array_initialization -/* helper symbol for array_initialization */ -%type array_initial_elements_list -%type array_initial_elements -%type array_initial_element - -%type structure_type_declaration -%type structure_specification -%type initialized_structure -%type structure_declaration -/* helper symbol for structure_declaration */ -%type structure_element_declaration_list -%type structure_element_declaration -%type structure_element_name -%type structure_initialization -/* helper symbol for structure_initialization */ -%type structure_element_initialization_list -%type structure_element_initialization - -//%type string_type_name -%type string_type_declaration -/* helper symbol for string_type_declaration */ -%type string_type_declaration_size -/* helper symbol for string_type_declaration */ -%type string_type_declaration_init - -%token ASSIGN -%token DOTDOT /* ".." */ -%token TYPE -%token END_TYPE -%token ARRAY -%token OF -%token STRUCT -%token END_STRUCT - - - -/*********************/ -/* B 1.4 - Variables */ -/*********************/ -%type variable -%type symbolic_variable -/* helper symbol for prog_cnxn */ -%type any_symbolic_variable -%type variable_name - - - - -/********************************************/ -/* B.1.4.1 Directly Represented Variables */ -/********************************************/ -/* Done totally within flex... - location_prefix - size_prefix -*/ -%token direct_variable_token -//%type direct_variable - - -/*************************************/ -/* B.1.4.2 Multi-element Variables */ -/*************************************/ -%type multi_element_variable -/* helper symbol for any_symbolic_variable */ -%type any_multi_element_variable -%type array_variable -/* helper symbol for any_symbolic_variable */ -%type any_array_variable -%type subscripted_variable -/* helper symbol for any_symbolic_variable */ -%type any_subscripted_variable -%type subscript_list -%type subscript -%type structured_variable -/* helper symbol for any_symbolic_variable */ -%type any_structured_variable -%type record_variable -/* helper symbol for any_symbolic_variable */ -%type any_record_variable -%type field_selector - - -/******************************************/ -/* B 1.4.3 - Declaration & Initialisation */ -/******************************************/ -%type input_declarations -/* helper symbol for input_declarations */ -%type input_declaration_list -%type input_declaration -%type edge_declaration -/* en_param_declaration is not in the standard, but should be! */ -%type en_param_declaration -%type var_init_decl -%type var1_init_decl -%type var1_list -%type array_var_init_decl -%type structured_var_init_decl -%type fb_name_decl -/* helper symbol for fb_name_decl */ -%type fb_name_list_with_colon -/* helper symbol for fb_name_list_with_colon */ -%type var1_list_with_colon -// %type fb_name_list -// %type fb_name -%type output_declarations -%type var_output_init_decl -%type var_output_init_decl_list -/* eno_param_declaration is not in the standard, but should be! */ -%type eno_param_declaration -%type input_output_declarations -/* helper symbol for input_output_declarations */ -%type var_declaration_list -%type var_declaration -%type temp_var_decl -%type var1_declaration -%type array_var_declaration -%type structured_var_declaration -%type var_declarations -%type retentive_var_declarations -%type located_var_declarations -/* helper symbol for located_var_declarations */ -%type located_var_decl_list -%type located_var_decl -%type external_var_declarations -/* helper symbol for external_var_declarations */ -%type external_declaration_list -%type external_declaration -%type global_var_name -%type global_var_declarations -/* helper symbol for global_var_declarations */ -%type global_var_decl_list -%type global_var_decl -%type global_var_spec -%type located_var_spec_init -%type location -%type global_var_list -%type string_var_declaration -%type single_byte_string_var_declaration -%type single_byte_string_spec -%type double_byte_string_var_declaration -%type double_byte_string_spec -%type incompl_located_var_declarations -/* helper symbol for incompl_located_var_declarations */ -%type incompl_located_var_decl_list -%type incompl_located_var_decl -%type incompl_location -%type var_spec -/* helper symbol for var_spec */ -%type string_spec -/* intermediate helper symbol for: - * - non_retentive_var_decls - * - var_declarations - */ -%type var_init_decl_list - -%token incompl_location_token - -%token VAR_INPUT -%token VAR_OUTPUT -%token VAR_IN_OUT -%token VAR_EXTERNAL -%token VAR_GLOBAL -%token END_VAR -%token RETAIN -%token NON_RETAIN -%token R_EDGE -%token F_EDGE -%token AT - - -/***********************/ -/* B 1.5.1 - Functions */ -/***********************/ -// %type function_name -/* helper symbol for IL language */ -%type function_name_no_clashes -%type function_name_simpleop_clashes -//%type function_name_expression_clashes -/* helper symbols for ST language */ -//%type function_name_NOT_clashes -%type function_name_no_NOT_clashes - -//%type standard_function_name -/* helper symbols for IL language */ -%type standard_function_name_no_clashes -%type standard_function_name_simpleop_clashes -%type standard_function_name_expression_clashes -/* helper symbols for ST language */ -%type standard_function_name_NOT_clashes -%type standard_function_name_no_NOT_clashes - -%type derived_function_name -%type function_declaration -/* helper symbol for function_declaration */ -%type function_name_declaration -%type io_var_declarations -%type function_var_decls -%type function_body -%type var2_init_decl -/* intermediate helper symbol for function_declaration */ -%type io_OR_function_var_declarations_list -/* intermediate helper symbol for function_var_decls */ -%type var2_init_decl_list - -%token standard_function_name_token - -%token FUNCTION -%token END_FUNCTION -%token CONSTANT - - -/*****************************/ -/* B 1.5.2 - Function Blocks */ -/*****************************/ -%type function_block_type_name -%type standard_function_block_name -%type derived_function_block_name -%type function_block_declaration -%type other_var_declarations -%type temp_var_decls -%type non_retentive_var_decls -%type function_block_body -/* intermediate helper symbol for function_declaration */ -%type io_OR_other_var_declarations_list -/* intermediate helper symbol for temp_var_decls */ -%type temp_var_decls_list - -%token standard_function_block_name_token - -%token FUNCTION_BLOCK -%token END_FUNCTION_BLOCK -%token VAR_TEMP -// %token END_VAR -%token VAR -// %token NON_RETAIN -// %token END_VAR - - -/**********************/ -/* B 1.5.3 - Programs */ -/**********************/ -%type program_type_name -%type program_declaration -/* helper symbol for program_declaration */ -%type program_var_declarations_list - -%token PROGRAM -%token END_PROGRAM - - -/********************************************/ -/* B 1.6 Sequential Function Chart elements */ -/********************************************/ - -%type sequential_function_chart -%type sfc_network -%type initial_step -%type step -%type action_association_list -%type step_name -%type action_association -/* helper symbol for action_association */ -%type indicator_name_list -%type action_name -%type action_qualifier -%type qualifier -%type timed_qualifier -%type action_time -%type indicator_name -%type transition -%type steps -%type step_name_list -%type transition_priority -%type transition_condition -%type action -%type action_body -%type transition_name - - -// %token ASSIGN -%token ACTION -%token END_ACTION - -%token TRANSITION -%token END_TRANSITION -%token FROM -%token TO -%token PRIORITY - -%token INITIAL_STEP -%token STEP -%token END_STEP - -%token L -%token D -%token SD -%token DS -%token SL - -%token N -%token P -/* NOTE: the following two clash with the R and S IL operators. - * It will have to be handled when we include parsing of SFC... - */ -/* -%token R -%token S -*/ - - -/********************************/ -/* B 1.7 Configuration elements */ -/********************************/ -%type configuration_name -%type resource_type_name -%type configuration_declaration -// helper symbol for -// - configuration_declaration -// - resource_declaration -// -%type optional_global_var_declarations -// helper symbol for configuration_declaration -%type optional_access_declarations -// helper symbol for configuration_declaration -%type optional_instance_specific_initializations -// helper symbol for configuration_declaration -%type resource_declaration_list -%type resource_declaration -%type single_resource_declaration -// helper symbol for single_resource_declaration -%type task_configuration_list -// helper symbol for single_resource_declaration -%type program_configuration_list -%type resource_name -// %type access_declarations -// helper symbol for access_declarations -// %type access_declaration_list -// %type access_declaration -// %type access_path -// helper symbol for access_path -%type any_fb_name_list -%type global_var_reference -// %type access_name -%type program_output_reference -%type program_name -// %type direction -%type task_configuration -%type task_name -%type task_initialization -// 3 helper symbols for task_initialization -%type task_initialization_single -%type task_initialization_interval -%type task_initialization_priority - -%type data_source -%type program_configuration -// helper symbol for program_configuration -%type optional_task_name -// helper symbol for program_configuration -%type optional_prog_conf_elements -%type prog_conf_elements -%type prog_conf_element -%type fb_task -%type prog_cnxn -%type prog_data_source -%type data_sink -%type instance_specific_initializations -// helper symbol for instance_specific_initializations -%type instance_specific_init_list -%type instance_specific_init -// helper symbol for instance_specific_init -%type fb_initialization - -%type prev_declared_global_var_name -%token prev_declared_global_var_name_token - -%type prev_declared_program_name -%token prev_declared_program_name_token - -%type prev_declared_resource_name -%token prev_declared_resource_name_token - -%token prev_declared_configuration_name_token - -// %type prev_declared_task_name -// %token prev_declared_task_name_token - -%token CONFIGURATION -%token END_CONFIGURATION -%token TASK -%token RESOURCE -%token ON -%token END_RESOURCE -%token VAR_CONFIG -%token VAR_ACCESS -// %token END_VAR -%token WITH -// %token PROGRAM -// %token RETAIN -// %token NON_RETAIN -// %token PRIORITY -%token SINGLE -%token INTERVAL -%token READ_WRITE -%token READ_ONLY - - -/***********************************/ -/* B 2.1 Instructions and Operands */ -/***********************************/ -%type instruction_list -%type il_instruction -%type il_incomplete_instruction -%type label -%type il_simple_operation -// helper symbol for il_simple_operation -//%type il_simple_operator_clash_il_operand -%type il_expression -%type il_jump_operation -%type il_fb_call -%type il_formal_funct_call -// helper symbol for il_formal_funct_call -%type il_expr_operator_clash_eol_list -%type il_operand -%type il_operand_list -// helper symbol for il_simple_operation -%type il_operand_list2 -%type simple_instr_list -%type il_simple_instruction -%type il_param_list -%type il_param_instruction_list -%type il_param_instruction -%type il_param_last_instruction -%type il_param_assignment -%type il_param_out_assignment - -%token EOL - - -/*******************/ -/* B 2.2 Operators */ -/*******************/ -%token sendto_identifier_token -%type sendto_identifier - -%type LD_operator -%type LDN_operator -%type ST_operator -%type STN_operator -%type NOT_operator -%type S_operator -%type R_operator -%type S1_operator -%type R1_operator -%type CLK_operator -%type CU_operator -%type CD_operator -%type PV_operator -%type IN_operator -%type PT_operator -%type AND_operator -%type AND2_operator -%type OR_operator -%type XOR_operator -%type ANDN_operator -%type ANDN2_operator -%type ORN_operator -%type XORN_operator -%type ADD_operator -%type SUB_operator -%type MUL_operator -%type DIV_operator -%type MOD_operator -%type GT_operator -%type GE_operator -%type EQ_operator -%type LT_operator -%type LE_operator -%type NE_operator -%type CAL_operator -%type CALC_operator -%type CALCN_operator -%type RET_operator -%type RETC_operator -%type RETCN_operator -%type JMP_operator -%type JMPC_operator -%type JMPCN_operator - -%type il_simple_operator -%type il_simple_operator_clash -%type il_simple_operator_clash1 -%type il_simple_operator_clash2 -%type il_simple_operator_noclash - -//%type il_expr_operator -%type il_expr_operator_clash -%type il_expr_operator_noclash - -%type il_assign_operator -%type il_assign_out_operator -%type il_call_operator -%type il_return_operator -%type il_jump_operator - - -%token LD -%token LDN -%token ST -%token STN -%token NOT -%token S -%token R -%token S1 -%token R1 -%token CLK -%token CU -%token CD -%token PV -%token IN -%token PT -%token AND -%token AND2 /* character '&' in the source code*/ -%token OR -%token XOR -%token ANDN -%token ANDN2 /* characters '&N' in the source code */ -%token ORN -%token XORN -%token ADD -%token SUB -%token MUL -%token DIV -%token MOD -%token GT -%token GE -%token EQ -%token LT -%token LE -%token NE -%token CAL -%token CALC -%token CALCN -%token RET -%token RETC -%token RETCN -%token JMP -%token JMPC -%token JMPCN - -%token SENDTO /* "=>" */ - - -/***********************/ -/* B 3.1 - Expressions */ -/***********************/ -/* NOTE: - * - * - unary_operator, multiply_operator, - * add_operator and comparison_operator - * are not required. Their values are integrated - * directly into other rules... - */ -%type expression -%type xor_expression -%type and_expression -%type comparison -%type equ_expression -// %type comparison_operator -%type add_expression -// %type add_operator -%type term -// %type multiply_operator -%type power_expression -%type unary_expression -// %type unary_operator -%type primary_expression -%type non_negative_primary_expression -/* intermediate helper symbol for primary_expression */ -%type function_invocation - -// %token AND -// %token XOR -// %token OR -// %token MOD -// %token NOT -%token OPER_NE -%token OPER_GE -%token OPER_LE -%token OPER_EXP - - -/********************/ -/* B 3.2 Statements */ -/********************/ -%type statement_list -%type statement - - - -/*********************************/ -/* B 3.2.1 Assignment Statements */ -/*********************************/ -%type assignment_statement -// %token ASSIGN /* ":=" */ - - -/*****************************************/ -/* B 3.2.2 Subprogram Control Statements */ -/*****************************************/ -%type subprogram_control_statement -%type return_statement -%type fb_invocation -// %type param_assignment -%type param_assignment_formal -%type param_assignment_nonformal -/* helper symbols for fb_invocation */ -%type param_assignment_formal_list -%type param_assignment_nonformal_list - -// %token ASSIGN -// %token SENDTO /* "=>" */ -%token RETURN - - -/********************************/ -/* B 3.2.3 Selection Statements */ -/********************************/ -%type selection_statement -%type if_statement -%type case_statement -%type case_element -%type case_list -%type case_list_element -/* helper symbol for if_statement */ -%type elseif_statement_list -/* helper symbol for elseif_statement_list */ -%type elseif_statement -/* helper symbol for case_statement */ -%type case_element_list - -%token IF -%token THEN -%token ELSIF -%token ELSE -%token END_IF - -%token CASE -// %token OF -// %token ELSE -%token END_CASE - - - -/********************************/ -/* B 3.2.4 Iteration Statements */ -/********************************/ -%type iteration_statement -%type for_statement -%type control_variable -%type while_statement -%type repeat_statement -%type exit_statement -/* Integrated directly into for_statement */ -// %type for_list - -%token FOR -// %token ASSIGN -// %token TO -%token BY -%token DO -%token END_FOR - -%token WHILE -// %token DO -%token END_WHILE - -%token REPEAT -%token UNTIL -%token END_REPEAT - -%token EXIT - - -%% - - - - -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ -/********************************************************/ - - -start: - library {$$ = $1;} -; - - -/**********************************************************************************/ -/* B XXX - Things that are missing from the standard, but should have been there! */ -/**********************************************************************************/ - - -/* the pragmas... */ - - -disable_code_generation_pragma: - disable_code_generation_pragma_token {$$ = new disable_code_generation_pragma_c(locloc(@$));} - -enable_code_generation_pragma: - enable_code_generation_pragma_token {$$ = new enable_code_generation_pragma_c(locloc(@$));} - -pragma: - pragma_token {$$ = new pragma_c($1, locloc(@$));} - -any_pragma: - disable_code_generation_pragma -| enable_code_generation_pragma -| pragma -; - - -/* EN/ENO */ -/* Tese tokens are essentially used as variable names, so we handle them - * similarly to these... - */ -en_identifier: - EN {$$ = new identifier_c("EN", locloc(@$));} -; - -eno_identifier: - ENO {$$ = new identifier_c("ENO", locloc(@$));} -; - - - -/*************************************/ -/* Prelimenary helpful constructs... */ -/*************************************/ - -/* NOTE: - * short version: - * identifier is used for previously undeclared identifiers - * any_identifier is used when any identifier, previously - * declared or not, is required in the syntax. - * - * long version: - * When flex comes across an identifier, it first - * searches through the currently declared variables, - * functions, types, etc... to determine if it has - * been previously declared. - * Only if the identifier has not yet been declared - * will it return an identifier_token (later turned into - * an identifier symbol by the bison generated syntax parser). - * - * Some constructs in the syntax, such as when calling - * a function 'F(var1 := 1; var2 := 2);', will accept _any_ - * identifier in 'var1', even if it has been previously - * declared in the current scope, since var1 belongs to - * another scope (the variables declared in function F). - * - * For the above reason, we need to define the symbol - * any_identifier. All the symbols that may become an - * any_identifier are expected to be stored in the - * abstract syntax as a identifier_c - */ -/* NOTE: - * Type names, function names, function block type names and - * program type names are considerd keywords once they are defined, - * so may no longer be used for variable names! - * BUT the spec is confusing on this issue, as it is not clear when - * a function name should be considered as defined. If it is to be - * considered defined only from the location from where it is declared - * and onwards, it means that before it is declared its name may be - * used for variable names! - * This means that we must allow names previously used for functions - * (et. al.) to also constitue an any_identifier! - */ -any_identifier: - identifier -| prev_declared_fb_name -| prev_declared_variable_name -/**/ -| prev_declared_enumerated_type_name -| prev_declared_simple_type_name -| prev_declared_subrange_type_name -| prev_declared_array_type_name -| prev_declared_structure_type_name -| prev_declared_string_type_name -| prev_declared_derived_function_name -| prev_declared_derived_function_block_name -| prev_declared_program_type_name -/**/ -| prev_declared_resource_name -| prev_declared_program_name -| prev_declared_global_var_name -; - - -prev_declared_variable_name: prev_declared_variable_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_fb_name: prev_declared_fb_name_token {$$ = new identifier_c($1, locloc(@$));}; - -prev_declared_simple_type_name: prev_declared_simple_type_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_subrange_type_name: prev_declared_subrange_type_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_enumerated_type_name: prev_declared_enumerated_type_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_array_type_name: prev_declared_array_type_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_structure_type_name: prev_declared_structure_type_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_string_type_name: prev_declared_string_type_name_token {$$ = new identifier_c($1, locloc(@$));}; - -prev_declared_derived_function_name: prev_declared_derived_function_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_derived_function_block_name: prev_declared_derived_function_block_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_program_type_name: prev_declared_program_type_name_token {$$ = new identifier_c($1, locloc(@$));}; - - - -/***************************/ -/* B 0 - Programming Model */ -/***************************/ -library: - /* empty */ - {if (tree_root == NULL) - tree_root = new library_c(); - $$ = (list_c *)tree_root; - } -| library library_element_declaration - {$$ = $1; $$->add_element($2);} -| library any_pragma - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| library error library_element_declaration - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unknown syntax error."); yyerrok;} -| library error END_OF_INPUT - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unknown syntax error."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -library_element_declaration: - data_type_declaration -| function_declaration -| function_block_declaration -| program_declaration -| configuration_declaration -; - - - -/*******************************************/ -/* B 1.1 - Letters, digits and identifiers */ -/*******************************************/ -/* NOTE: the spec defines identifier as: - * identifier ::= (letter|('_' (letter|digit))) {['_'] (letter|digit)} - * In essence, any sequence of letters or digits, starting with a letter - * or '_'. - * - * On section 2.1.3 (pg 26) , the spec states - * "The keywords listed in annex C shall not be used for any other purpose, - * e.g., variable names or extensions as defined in 1.5.1." - * (NOTE: the spec itself does not follow this rule, as it defines standard - * functions with names identidal to keywords, e.g. 'MOD', 'NOT' !!. This is - * another issue altogether, and is worked around somewhere else...) - * - * This means that we must re-define indentifier so as to exclude - * any keywords defined in annex C. - * - * Note also that the list includes - * - Data type names - * - Function names - * - Function Block names - * This means that any named used for a function name, data type name - * or function block name, essentially becomes a keyword, and may therefore - * no longer be re-used for any other use! (see NOTE 2) - * - * In our case, excluding the keywords is achieved in the lexical parser, - * by two mechanisms: - * (1) giving higher priority to the keywords (tokens) than to identifiers, - * so when the lexical parser finds a keyword it will be parsed as a - * token before being parsed as an identifier. - * (2) when an identifier is found that is not a keyword, the lexical parser - * then looks in the global symbol table, and will not return an identifier - * if the name has been previously used as a data type name, function name, - * or function block name! (In these cases it will return a - * prev_declared_function_name_token, etc...). - * - * Unfortunately, the language (especially IL) uses tokens that are - * not defined as keywords in the spec (e.g. 'IN', 'R1', 'S1', 'PT', etc...)! - * This means that it is valid to name a function 'IN', a variable 'PT', etc... - * In order to solve this potential ambiguity, flex only parses the above - * identifiers as keywords / tokens if we are currently parsing IL code. - * When parsing all code other than IL code, the above identifiers are treated - * just like any other identifier. - * - * - * - * - * NOTE 2: - * I (Mario) find it strange that the writers of the spec really want - * names previously used for function names, data type names or function - * block names, to become full fledged keywords. I understand that they - * do not want these names being used as variable names, but how about - * enumeration values? How about structure element names? - * If we interpret the spec literally, these would not be accepted, - * which would probably burden the programmer quite a bit, in making sure - * all these name don't clash! - * - * - * - * NOTE 3: The keywords, as specified in Annex C are... - * - * - Data type names - * - Function names - * - Function Block names - * - ACTION...END_ACTION - * - ARRAY...OF - * - AT - * - CASE...OF...ELSE...END_CASE - * - CONFIGURATION...END_CONFIGURATION - * - CONSTANT - * - EN, ENO - * - EXIT - * - FALSE - * - F_EDGE - * - FOR...TO...BY...DO...END_FOR - * - FUNCTION...END_FUNCTION - * - FUNCTION_BLOCK...END_FUNCTION_BLOCK - * - IF...THEN...ELSIF...ELSE...END_IF - * - INITIAL_STEP...END_STEP - * - NOT, MOD, AND, XOR, OR - * - PROGRAM...WITH... - * - PROGRAM...END_PROGRAM - * - R_EDGE - * - READ_ONLY, READ_WRITE - * - REPEAT...UNTIL...END_REPEAT - * - RESOURCE...ON...END_RESOURCE - * - RETAIN, NON_RETAIN - * - RETURN - * - STEP...END_STEP - * - STRUCT...END_STRUCT - * - TASK - * - TRANSITION...FROM...TO...END_TRANSITION - * - TRUE - * - TYPE...END_TYPE - * - VAR...END_VAR - * - VAR_INPUT...END_VAR - * - VAR_OUTPUT...END_VAR - * - VAR_IN_OUT...END_VAR - * - VAR_TEMP...END_VAR - * - VAR_EXTERNAL...END_VAR - * - VAR_ACCESS...END_VAR - * - VAR_CONFIG...END_VAR - * - VAR_GLOBAL...END_VAR - * - WHILE...DO...END_WHILE - * - WITH - */ - -identifier: - identifier_token {$$ = new identifier_c($1, locloc(@$));} -; - - - -/*********************/ -/* B 1.2 - Constants */ -/*********************/ -constant: - numeric_literal -| character_string -| time_literal -| bit_string_literal -| boolean_literal -/* NOTE: in order to remove reduce/reduce conflicts, - * [between -9.5 being parsed as - * (i) a signed real, - * (ii) or as a real preceded by the '-' operator - * ] - * we need to define a variant of the constant construct - * where any constant is never preceded by the '-' character. - * In order to do this, we have borugh the signed_real - * directly into the definition of the constant construct - * (so we can define another non_negative_constant - * construct that does not include it!) - */ -| signed_real -/* NOTE: in order to remove reduce/reduce conflicts, - * unsigned_integer, signed_integer, binary_integer, octal_integer - * and hex_integer have been integrated directly into - * the constants construct, instead of belonging to - * both the bit_string_literal or integer_literal - * construct. - */ -/* NOTE: unsigned_integer, although used in some - * rules, is not defined in the spec! - * We therefore replaced unsigned_integer as integer - */ -/*| integer {} */ /* i.e. an unsigned_integer */ /* NOTE: already included as a signed integer! */ -| signed_integer -| binary_integer -| octal_integer -| hex_integer -; - - -/* NOTE: in order to remove reduce/reduce conflicts, - * [between -9.5 being parsed as - * (i) a signed real, - * (ii) or as a real preceded by the '-' operator - * ] - * we need to define a variant of the constant construct - * where any constant is never preceded by the '-' character. - * In order to do this, we have borugh the signed_real - * directly into the definition of the constant construct - * (so we can define another non_negative_constant - * construct that does not include it!) - */ -non_negative_constant: - numeric_literal -| character_string -| time_literal -| bit_string_literal -| boolean_literal -/* NOTE: in order to remove reduce/reduce conflicts, - * [between -9.5 being parsed as - * (i) a signed real, - * (ii) or as a real preceded by the '-' operator - * ] - * we need to define a variant of the constant construct - * where any constant is never preceded by the '-' character. - * In order to do this, we have borugh the signed_real - * directly into the definition of the constant construct - * (so we can define another non_negative_constant - * construct that does not include it!) - */ -/* | signed_real */ -| real /* an unsigned real */ -/* NOTE: in order to remove reduce/reduce conflicts, - * unsigned_integer, signed_integer, binary_integer, octal_integer - * and hex_integer have been integrated directly into - * the constants construct, instead of belonging to - * both the bit_string_literal or integer_literal - * construct. - */ -/* NOTE: unsigned_integer, although used in some - * rules, is not defined in the spec! - * We therefore replaced unsigned_integer as integer - */ -| integer /* i.e. an unsigned_integer */ -/* | signed_integer */ -| binary_integer -| octal_integer -| hex_integer -; - - -/******************************/ -/* B 1.2.1 - Numeric Literals */ -/******************************/ -/* NOTES: - * - * - integer is parsed by flex, but signed_integer - * is parsed by bison. Flex cannot parse a signed - * integer correctly! For example: '123+456' - * would be parsed by flex as an {integer} {signed_integer} - * instead of {integer} '+' {integer} - * - * - Neither flex nor bison can parse a real_literal - * completely (and correctly). - * Note that we cannot use the definition of real in bison as - * real: signed_integer '.' integer [exponent] - * exponent: {'E'|'e'} ['+'|'-'] integer - * because 123e45 would be parsed by flex as - * integer (123) identifier (e45). - * I.e., flex never hands over an 'e' directly to - * bison, but rather interprets it as an identifier. - * I guess we could jump through hoops and get it - * working in bison, but the following alternative - * seems more straight forward... - * - * We therefore had to break up the definition of - * real_literal in discrete parts: - * real_literal: [real_type_name '#'] singned_real - * signed_real: ['+'|'-'] real - * Flex handles real, while bison handles signed_real - * and real_literal. - * - * - According to the spec, integer '.' integer - * may be reduced to either a real or a fixed_point. - * It is nevertheless possible to figure out from the - * context which of the two rules should be used in - * the reduction. - * Unfortunately, due to the issue described above - * regarding the exponent of a real, the syntax - * integer '.' integer - * must be parsed by flex as a single token (i.e. - * fixed_point_token). This means we must add fixed_point - * to the definition of real! - * - * - The syntax also uses a construct - * fixed_point: integer ['.' integer] - * Notice that real is not defined based on fixed point, - * but rather off integer thus: - * real: integer '.' integer [exponent] - * This means that a real may not be composed of a single - * integer, unlike the construct fixed_point! - * This also means that a - * integer '.' integer - * could be reduced to either a real or a fixed_point - * construct. It is probably possible to decide by looking - * at the context, BUT: - * Unfortunatley, due to the reasons explained way above, - * a real (with an exponent) has to be handled by flex as a - * whole. This means that we cannot leave to bison (the syntax - * parser) the decision of how to reduce an - * integer '.' integer - * (either to real or to fixed_point) - * The decision on how to reduce it would need to be done by - * ther lexical analyser (i.e. flex). But flex cannot do this - * sort of thing. - * The solution I (Mario) adopted is to have flex return - * a real_token on (notice that exponent is no longer optional) - * integer '.' integer exponent - * and to return a fixed_point_token when it finds - * integer '.' integer - * We now redefine real and fixed_point to be - * fixed_point: fixed_point_token | integer - * real: real_token | fixed_point_token - */ -real: - real_token {$$ = new real_c($1, locloc(@$));} -| fixed_point_token {$$ = new real_c($1, locloc(@$));} -; - -integer: integer_token {$$ = new integer_c($1, locloc(@$));}; -binary_integer: binary_integer_token {$$ = new binary_integer_c($1, locloc(@$));}; -octal_integer: octal_integer_token {$$ = new octal_integer_c($1, locloc(@$));}; -hex_integer: hex_integer_token {$$ = new hex_integer_c($1, locloc(@$));}; - -numeric_literal: - integer_literal -| real_literal -; - - -integer_literal: - integer_type_name '#' signed_integer - {$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));} -| integer_type_name '#' binary_integer - {$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));} -| integer_type_name '#' octal_integer - {$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));} -| integer_type_name '#' hex_integer - {$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));} -/* NOTE: see note in the definition of constant for reason - * why signed_integer, binary_integer, octal_integer - * and hex_integer are missing here! - */ -/* ERROR_CHECK_BEGIN */ -| integer_type_name signed_integer - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} -| integer_type_name binary_integer - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} -| integer_type_name octal_integer - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} -| integer_type_name hex_integer - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} -| integer_type_name '#' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for integer literal.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value for integer literal."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -signed_integer: - integer -| '+' integer {$$ = $2;} -| '-' integer {$$ = new neg_integer_c($2, locloc(@$));} -; - - -real_literal: -/* NOTE: see note in the definition of constant for reason - * why signed_real is missing here! - */ -/* signed_real */ - real_type_name '#' signed_real - {$$ = new real_literal_c($1, $3, locf(@1), locl(@3));} -/* ERROR_CHECK_BEGIN */ -| real_type_name signed_real - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between real type name and value in real literal."); yynerrs++;} -| real_type_name '#' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for real literal.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value for real literal."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -signed_real: - real -| '+' real {$$ = $2;} -| '-' real {$$ = new neg_real_c($2, locloc(@2));} -; - - - -bit_string_literal: - bit_string_type_name '#' integer /* i.e. unsigned_integer */ - {$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));} -| bit_string_type_name '#' binary_integer - {$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));} -| bit_string_type_name '#' octal_integer - {$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));} -| bit_string_type_name '#' hex_integer - {$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));} -/* NOTE: see note in the definition of constant for reason - * why unsigned_integer, binary_integer, octal_integer - * and hex_integer are missing here! - */ -/* NOTE: see note under the B 1.2.1 section of token - * and grouping type definition for reason why the use of - * bit_string_type_name, although seemingly incorrect, is - * really correct here! - */ -/* ERROR_CHECK_BEGIN */ -| bit_string_type_name integer - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} -| bit_string_type_name binary_integer - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} -| bit_string_type_name octal_integer - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} -| bit_string_type_name hex_integer - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} -| bit_string_type_name '#' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for bit string literal.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value for bit string literal."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -boolean_literal: - boolean_true_literal_token - {$$ = new boolean_literal_c(new bool_type_name_c(locloc(@$)), - new boolean_true_c(locloc(@$)), - locloc(@$)); - } -| boolean_false_literal_token - {$$ = new boolean_literal_c(new bool_type_name_c(locloc(@$)), - new boolean_false_c(locloc(@$)), - locloc(@$)); - } -| safeboolean_true_literal_token - {$$ = new boolean_literal_c(new safebool_type_name_c(locloc(@$)), - new boolean_true_c(locloc(@$)), - locloc(@$)); - } -| safeboolean_false_literal_token - {$$ = new boolean_literal_c(new safebool_type_name_c(locloc(@$)), - new boolean_false_c(locloc(@$)), - locloc(@$)); - } -| FALSE - {$$ = new boolean_literal_c(NULL, - new boolean_false_c(locloc(@$)), - locloc(@$)); - } -| TRUE - {$$ = new boolean_literal_c(NULL, - new boolean_true_c(locloc(@$)), - locloc(@$)); - } -/* -| BOOL '#' '1' {} -| BOOL '#' '0' {} -*/ -/* NOTE: the rules - * BOOL '#' '1' - * and - * BOOL '#' '0' - * do not work as expected... - * Consider that we are using 'BOOL' and '#' as tokens - * that flex hands over to bison (yacc). Because flex would - * then parse the single '1' or '0' as an integer, - * the rule in bison would have to be - * BOOL '#' integer, followed by verifying of the - * integer has the correct value! - * - * We therefore have flex return TRUE whenever it - * comes across 'TRUE' or 'BOOL#1', and FALSE whenever - * it comes across 'FALSE' or 'BOOL#0'. - * Note that this means that flex will parse "BOOL#01" - * as FALSE followed by an integer ('1'). - * Bison should detect this as an error, so we should - * be OK. - * - * Another option would be to change the rules to accept - * BOOL '#' integer - * but then check whether the integer has a correct - * value! At the moment I feel that the first option - * is more straight forward. - */ -; - - - -/*******************************/ -/* B 1.2.2 - Character Strings */ -/*******************************/ -/* Transform the tokens given us by flex into leafs */ -single_byte_character_string: single_byte_character_string_token - {$$ = new single_byte_character_string_c($1, locloc(@$));}; - -double_byte_character_string: double_byte_character_string_token - {$$ = new double_byte_character_string_c($1, locloc(@$));}; - - -character_string: - single_byte_character_string -| double_byte_character_string -; - - - - - -/***************************/ -/* B 1.2.3 - Time Literals */ -/***************************/ -time_literal: - time_of_day -| date -| date_and_time -| duration -; - - -/************************/ -/* B 1.2.3.1 - Duration */ -/************************/ -duration: -/* (T | TIME) '#' ['-'] interval */ -/* NOTE: since TIME is also a data type, it is a keyword - * and may therefore be handled by a token. - * - * Unfortunately T is not a data type, and therefore - * not a keyword. This means that we may have variables named T! - * Flex cannot return the token TIME when it comes across a single T! - * - * We therefore have flex returning the token T_SHARP - * when it comes across 'T#' - */ - TIME '#' interval - {$$ = new duration_c(new time_type_name_c(locloc(@1)), NULL, $3, locloc(@$));} -| TIME '#' '-' interval - {$$ = new duration_c(new time_type_name_c(locloc(@1)), new neg_time_c(locloc(@$)), $4, locloc(@$));} -| T_SHARP interval - {$$ = new duration_c(new time_type_name_c(locloc(@1)), NULL, $2, locloc(@$));} -| T_SHARP '-' interval - {$$ = new duration_c(new time_type_name_c(locloc(@1)), new neg_time_c(locloc(@$)), $3, locloc(@$));} -| SAFETIME '#' interval - {$$ = new duration_c(new safetime_type_name_c(locloc(@1)), NULL, $3, locloc(@$));} -| SAFETIME '#' '-' interval - {$$ = new duration_c(new safetime_type_name_c(locloc(@1)), new neg_time_c(locloc(@$)), $4, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| TIME interval - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME' and interval in duration."); yynerrs++;} -| TIME '-' interval - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME' and interval in duration."); yynerrs++;} -| TIME '#' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for duration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value for duration."); yyclearin;} - yyerrok; - } -| T_SHARP error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no value defined for duration.");} - else {print_err_msg(locf(@2), locl(@2), "invalid value for duration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -interval: - days -| hours -| minutes -| seconds -| milliseconds -; - -integer_d: integer_d_token {$$ = new integer_c($1, locloc(@$));}; -integer_h: integer_h_token {$$ = new integer_c($1, locloc(@$));}; -integer_m: integer_m_token {$$ = new integer_c($1, locloc(@$));}; -integer_s: integer_s_token {$$ = new integer_c($1, locloc(@$));}; -integer_ms: integer_ms_token {$$ = new integer_c($1, locloc(@$));}; - -fixed_point_d: - fixed_point_d_token - {$$ = new fixed_point_c($1, locloc(@$));} -| integer_d -; - -fixed_point_h: - fixed_point_h_token - {$$ = new fixed_point_c($1, locloc(@$));} -| integer_h -; - -fixed_point_m: - fixed_point_m_token - {$$ = new fixed_point_c($1, locloc(@$));} -| integer_m -; - -fixed_point_s: - fixed_point_s_token - {$$ = new fixed_point_c($1, locloc(@$));} -| integer_s -; - -fixed_point_ms: - fixed_point_ms_token - {$$ = new fixed_point_c($1, locloc(@$));} -| integer_ms -; - - -fixed_point: - fixed_point_token - {$$ = new fixed_point_c($1, locloc(@$));} -| integer -; - - -days: -/* fixed_point ('d') */ - fixed_point_d - {$$ = new days_c($1, NULL, locloc(@$));} -/*| integer ('d') ['_'] hours */ -| integer_d hours - {$$ = new days_c($1, $2, locloc(@$));} -| integer_d '_' hours - {$$ = new days_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| integer_d '_' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for hours in duration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value for hours in duration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -hours: -/* fixed_point ('h') */ - fixed_point_h - {$$ = new hours_c($1, NULL, locloc(@$));} -/*| integer ('h') ['_'] minutes */ -| integer_h minutes - {$$ = new hours_c($1, $2, locloc(@$));} -| integer_h '_' minutes - {$$ = new hours_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| integer_h '_' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for minutes in duration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value for minutes in duration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ - -; - -minutes: -/* fixed_point ('m') */ - fixed_point_m - {$$ = new minutes_c($1, NULL, locloc(@$));} -/*| integer ('m') ['_'] seconds */ -| integer_m seconds - {$$ = new minutes_c($1, $2, locloc(@$));} -| integer_m '_' seconds - {$$ = new minutes_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| integer_m '_' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for seconds in duration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value for seconds in duration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -seconds: -/* fixed_point ('s') */ - fixed_point_s - {$$ = new seconds_c($1, NULL, locloc(@$));} -/*| integer ('s') ['_'] milliseconds */ -| integer_s milliseconds - {$$ = new seconds_c($1, $2, locloc(@$));} -| integer_s '_' milliseconds - {$$ = new seconds_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| integer_s '_' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for milliseconds in duration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value for milliseconds in duration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -milliseconds: -/* fixed_point ('ms') */ - fixed_point_ms - {$$ = new milliseconds_c($1, locloc(@$));} -; - - - -/************************************/ -/* B 1.2.3.2 - Time of day and Date */ -/************************************/ -time_of_day: - TIME_OF_DAY '#' daytime - {$$ = new time_of_day_c(new tod_type_name_c(locloc(@1)), $3, locloc(@$));} -| SAFETIME_OF_DAY '#' daytime - {$$ = new time_of_day_c(new safetod_type_name_c(locloc(@1)), $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| TIME_OF_DAY daytime - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME_OF_DAY' and daytime in time of day."); yynerrs++;} -| TIME_OF_DAY '#' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for time of day.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value for time of day."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -daytime: - day_hour ':' day_minute ':' day_second - {$$ = new daytime_c($1, $3, $5, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| ':' day_minute ':' day_second - {$$ = NULL; print_err_msg(locf(@1), locl(@4), "no value defined for hours in daytime."); yynerrs++;} -| error ':' day_minute ':' day_second - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid value defined for hours in daytime."); yyerrok;} -| day_hour day_minute ':' day_second - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between hours and minutes in daytime."); yynerrs++;} -| day_hour ':' ':' day_second - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no value defined for minutes in daytime."); yynerrs++;} -| day_hour ':' error ':' day_second - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value defined for minutes in daytime."); yyerrok;} -| day_hour ':' day_minute day_second - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "':' missing between minutes and seconds in daytime."); yynerrs++;} -| day_hour ':' day_minute ':' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@4), locf(@5), "no value defined for seconds in daytime.");} - else {print_err_msg(locf(@5), locl(@5), "invalid value for seconds in daytime."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -day_hour: integer; -day_minute: integer; -day_second: fixed_point; - - -date: - DATE '#' date_literal - {$$ = new date_c(new date_type_name_c(locloc(@1)), $3, locloc(@$));} -| D_SHARP date_literal - {$$ = new date_c(new date_type_name_c(locloc(@1)), $2, locloc(@$));} -| SAFEDATE '#' date_literal - {$$ = new date_c(new safedate_type_name_c(locloc(@1)), $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| DATE date_literal - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'DATE' and date literal in date."); yynerrs++;} -| DATE '#' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for date.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value for date."); yyclearin;} - yyerrok; - } -| D_SHARP error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no value defined for date.");} - else {print_err_msg(locf(@2), locl(@2), "invalid value for date."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -date_literal: - year '-' month '-' day - {$$ = new date_literal_c($1, $3, $5, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| '-' month '-' day - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no value defined for year in date literal."); yynerrs++;} -| year month '-' day - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'-' missing between year and month in date literal."); yynerrs++;} -| year '-' '-' day - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no value defined for month in date literal."); yynerrs++;} -| year '-' error '-' day - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value defined for month in date literal."); yyerrok;} -| year '-' month day - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "'-' missing between month and day in date literal."); yynerrs++;} -| year '-' month '-' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@4), locf(@5), "no value defined for day in date literal.");} - else {print_err_msg(locf(@5), locl(@5), "invalid value for day in date literal."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -year: integer; -month: integer; -day: integer; - - -date_and_time: - DATE_AND_TIME '#' date_literal '-' daytime - {$$ = new date_and_time_c(new dt_type_name_c(locloc(@1)), $3, $5, locloc(@$));} -| SAFEDATE_AND_TIME '#' date_literal '-' daytime - {$$ = new date_and_time_c(new safedt_type_name_c(locloc(@1)), $3, $5, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| DATE_AND_TIME date_literal '-' daytime - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'DATE_AND_TIME' and date literal in date and time."); yynerrs++;} -| DATE_AND_TIME '#' '-' daytime - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no value defined for date literal in date and time."); yynerrs++;} -| DATE_AND_TIME '#' error '-' daytime - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value for date literal in date and time."); yyerrok;} -| DATE_AND_TIME '#' date_literal daytime - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "'-' missing between date literal and daytime in date and time."); yynerrs++;} -| DATE_AND_TIME '#' date_literal '-' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@4), locf(@5), "no value defined for daytime in date and time.");} - else {print_err_msg(locf(@5), locl(@5), "invalid value for daytime in date and time."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - - - - - -/**********************/ -/* B 1.3 - Data Types */ -/**********************/ -/* Strangely, the following symbol does seem to be required! */ -/* -data_type_name: - non_generic_type_name -| generic_type_name -; -*/ - -non_generic_type_name: - elementary_type_name -| derived_type_name -; - - - -/***********************************/ -/* B 1.3.1 - Elementary Data Types */ -/***********************************/ - /******************************************************/ - /* SAFExxxx Symbols defined in */ - /* "Safety Software Technical Specification, */ - /* Part 1: Concepts and Function Blocks, */ - /* Version 1.0 – Official Release" */ - /* by PLCopen - Technical Committee 5 - 2006-01-31 */ - /******************************************************/ - -elementary_type_name: - numeric_type_name -| date_type_name -| bit_string_type_name -| elementary_string_type_name -| TIME {$$ = new time_type_name_c(locloc(@$));} -| BOOL {$$ = new bool_type_name_c(locloc(@$));} -/* NOTE: see note under the B 1.2.1 section of token - * and grouping type definition for reason why BOOL - * was added to this definition. - */ -| SAFETIME {$$ = new safetime_type_name_c(locloc(@$));} -| SAFEBOOL {$$ = new safebool_type_name_c(locloc(@$));} -; - -numeric_type_name: - integer_type_name -| real_type_name -; - -integer_type_name: - signed_integer_type_name -| unsigned_integer_type_name -; - -signed_integer_type_name: - SINT {$$ = new sint_type_name_c(locloc(@$));} -| INT {$$ = new int_type_name_c(locloc(@$));} -| DINT {$$ = new dint_type_name_c(locloc(@$));} -| LINT {$$ = new lint_type_name_c(locloc(@$));} -| SAFESINT {$$ = new safesint_type_name_c(locloc(@$));} -| SAFEINT {$$ = new safeint_type_name_c(locloc(@$));} -| SAFEDINT {$$ = new safedint_type_name_c(locloc(@$));} -| SAFELINT {$$ = new safelint_type_name_c(locloc(@$));} -; - -unsigned_integer_type_name: - USINT {$$ = new usint_type_name_c(locloc(@$));} -| UINT {$$ = new uint_type_name_c(locloc(@$));} -| UDINT {$$ = new udint_type_name_c(locloc(@$));} -| ULINT {$$ = new ulint_type_name_c(locloc(@$));} -| SAFEUSINT {$$ = new safeusint_type_name_c(locloc(@$));} -| SAFEUINT {$$ = new safeuint_type_name_c(locloc(@$));} -| SAFEUDINT {$$ = new safeudint_type_name_c(locloc(@$));} -| SAFEULINT {$$ = new safeulint_type_name_c(locloc(@$));} -; - -real_type_name: - REAL {$$ = new real_type_name_c(locloc(@$));} -| LREAL {$$ = new lreal_type_name_c(locloc(@$));} -| SAFEREAL {$$ = new safereal_type_name_c(locloc(@$));} -| SAFELREAL {$$ = new safelreal_type_name_c(locloc(@$));} -; - -date_type_name: - DATE {$$ = new date_type_name_c(locloc(@$));} -| TIME_OF_DAY {$$ = new tod_type_name_c(locloc(@$));} -| TOD {$$ = new tod_type_name_c(locloc(@$));} -| DATE_AND_TIME {$$ = new dt_type_name_c(locloc(@$));} -| DT {$$ = new dt_type_name_c(locloc(@$));} -| SAFEDATE {$$ = new safedate_type_name_c(locloc(@$));} -| SAFETIME_OF_DAY {$$ = new safetod_type_name_c(locloc(@$));} -| SAFETOD {$$ = new safetod_type_name_c(locloc(@$));} -| SAFEDATE_AND_TIME {$$ = new safedt_type_name_c(locloc(@$));} -| SAFEDT {$$ = new safedt_type_name_c(locloc(@$));} -; - - -bit_string_type_name: - BYTE {$$ = new byte_type_name_c(locloc(@$));} -| WORD {$$ = new word_type_name_c(locloc(@$));} -| DWORD {$$ = new dword_type_name_c(locloc(@$));} -| LWORD {$$ = new lword_type_name_c(locloc(@$));} -| SAFEBYTE {$$ = new safebyte_type_name_c(locloc(@$));} -| SAFEWORD {$$ = new safeword_type_name_c(locloc(@$));} -| SAFEDWORD {$$ = new safedword_type_name_c(locloc(@$));} -| SAFELWORD {$$ = new safelword_type_name_c(locloc(@$));} -/* NOTE: see note under the B 1.2.1 section of token - * and grouping type definition for reason why the BOOL - * was omitted from this definition. - */ -; - - -/* Helper symbol to concentrate the instantiation - * of STRING and WSTRING into a single location. - * - * These two elements show up in several other rules, - * but we want to create the equivalent abstract syntax - * in a single location of this file, in order to make - * possible future changes easier to edit... - */ -elementary_string_type_name: - STRING {$$ = new string_type_name_c(locloc(@$));} -| WSTRING {$$ = new wstring_type_name_c(locloc(@$));} -| SAFESTRING {$$ = new safestring_type_name_c(locloc(@$));} -| SAFEWSTRING {$$ = new safewstring_type_name_c(locloc(@$));} -; - - - -/********************************/ -/* B 1.3.2 - Generic data types */ -/********************************/ -/* Strangely, the following symbol does not seem to be required! */ -/* -generic_type_name: - ANY -| ANY_DERIVED -| ANY_ELEMENTARY -| ANY_MAGNITUDE -| ANY_NUM -| ANY_REAL -| ANY_INT -| ANY_BIT -| ANY_STRING -| ANY_DATE -; -*/ - - -/********************************/ -/* B 1.3.3 - Derived data types */ -/********************************/ - -derived_type_name: - single_element_type_name -| prev_declared_array_type_name -| prev_declared_structure_type_name -| prev_declared_string_type_name -; - -single_element_type_name: - prev_declared_simple_type_name -/* Include the following if arrays of function blocks are to be allowed! - * Since the standard does not allow them, - * we leave it commented out for the time being... - */ -//| prev_declared_derived_function_block_name -| prev_declared_subrange_type_name -| prev_declared_enumerated_type_name -; - -/* NOTE: in order to remove a reduce/reduce conflict, - * all occurences of simple_type_name, etc... - * have been replaced with identifier! - */ -/* -simple_type_name: identifier; -subrange_type_name: identifier; -enumerated_type_name: identifier; -array_type_name: identifier; -structure_type_name: identifier; -*/ - -data_type_declaration: - TYPE type_declaration_list END_TYPE - {$$ = new data_type_declaration_c($2, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| TYPE END_TYPE - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no data type declared in data type(s) declaration."); yynerrs++;} -| TYPE error type_declaration_list END_TYPE - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'TYPE' in data type(s) declaration."); yyerrok;} -| TYPE type_declaration_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed data type(s) declaration."); yyerrok;} -| TYPE error END_TYPE - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in data type(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - -/* helper symbol for data_type_declaration */ -type_declaration_list: - type_declaration ';' - {$$ = new type_declaration_list_c(locloc(@$)); $$->add_element($1);} -| type_declaration_list type_declaration ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| error ';' - {$$ = new type_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid data type declaration."); yyerrok;} -| type_declaration error - {$$ = new type_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of data type declaration."); yyerrok;} -| type_declaration_list type_declaration error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of data type declaration."); yyerrok;} -| type_declaration_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid data type declaration."); yyerrok;} -| type_declaration_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after data type declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - -type_declaration: - single_element_type_declaration -| array_type_declaration -| structure_type_declaration -| string_type_declaration -; - -single_element_type_declaration: - simple_type_declaration -| subrange_type_declaration -| enumerated_type_declaration -; - -simple_type_declaration: -/* simple_type_name ':' simple_spec_init */ - identifier ':' simple_spec_init - {$$ = new simple_type_declaration_c($1, $3, locloc(@$)); - library_element_symtable.insert($1, prev_declared_simple_type_name_token); - } -/* ERROR_CHECK_BEGIN */ -| error ':' simple_spec_init - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for data type declaration.");yyerrok;} -| identifier simple_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in simple type declaration."); yynerrs++;} -| identifier ':' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in data type declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid specification in data type declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -simple_spec_init: - simple_specification - /* The following commented line was changed to the - * next two lines so that we wouldn't - * have the first element of a simple_spec_init_c() - * pointing to another simple_spec_init_c! - */ -/* -| simple_specification ASSIGN constant - {$$ = new simple_spec_init_c($1, $3);} -*/ -| elementary_type_name ASSIGN constant - {$$ = new simple_spec_init_c($1, $3, locloc(@$));} -| prev_declared_simple_type_name ASSIGN constant - {$$ = new simple_spec_init_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| elementary_type_name constant - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in specification with initialization."); yynerrs++;} -| prev_declared_simple_type_name constant - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in specification with initialization."); yynerrs++;} -| elementary_type_name ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in specification with initialization.");} - else {print_err_msg(locf(@3), locl(@3), "invalid initial value in specification with initialization."); yyclearin;} - yyerrok; - } -| prev_declared_simple_type_name ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in specification with initialization.");} - else {print_err_msg(locf(@3), locl(@3), "invalid initial value in specification with initialization."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -/* When converting to C/C++, we need to know whether - * the elementary_type_name is being used in a variable - * declaration or elsewhere (ex. declaration of a derived - * type), so the abstract syntax has the elementary_type_name - * wrapped inside a simple_spec_init_c. - * The exact same thing occurs with prev_declared_simple_type_name. - * - * This is why in the definition of simple_spec_init, - * simple_specification was brocken up into its - * constituent components... - */ -simple_specification: -// elementary_type_name | simple_type_name - elementary_type_name - {$$ = new simple_spec_init_c($1, NULL, locloc(@$));} -| prev_declared_simple_type_name - {$$ = new simple_spec_init_c($1, NULL, locloc(@$));} -; - - -subrange_type_declaration: -/* subrange_type_name ':' subrange_spec_init */ - identifier ':' subrange_spec_init - {$$ = new subrange_type_declaration_c($1, $3, locloc(@$)); - library_element_symtable.insert($1, prev_declared_subrange_type_name_token); - } -/* ERROR_CHECK_BEGIN */ -| error ':' subrange_spec_init - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for subrange type declaration."); yyerrok;} -| identifier subrange_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in subrange type declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - -subrange_spec_init: - subrange_specification - {$$ = new subrange_spec_init_c($1, NULL, locloc(@$));} -| subrange_specification ASSIGN signed_integer - {$$ = new subrange_spec_init_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| subrange_specification signed_integer - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in subrange specification with initialization."); yynerrs++;} -| subrange_specification ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in subrange specification with initialization.");} - else {print_err_msg(locf(@3), locl(@3), "invalid initial value in subrange specification with initialization."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -subrange_specification: - integer_type_name '(' subrange ')' - {$$ = new subrange_specification_c($1, $3, locloc(@$));} -| prev_declared_subrange_type_name - {$$ = new subrange_specification_c($1, NULL, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| integer_type_name '(' ')' - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no subrange defined in subrange specification."); yynerrs++;} -| integer_type_name '(' error ')' - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid subrange defined in subrange specification."); yyerrok;} -| integer_type_name '(' subrange error - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing after subrange defined in subrange specification."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -subrange: - signed_integer DOTDOT signed_integer - {$$ = new subrange_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| signed_integer signed_integer - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'..' missing between bounds in subrange definition."); yynerrs++;} -| signed_integer DOTDOT error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for upper bound in subrange definition.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value for upper bound in subrange definition."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -enumerated_type_declaration: -/* enumerated_type_name ':' enumerated_spec_init */ - identifier ':' enumerated_spec_init - {$$ = new enumerated_type_declaration_c($1, $3, locloc(@$)); - library_element_symtable.insert($1, prev_declared_enumerated_type_name_token); - } -/* ERROR_CHECK_BEGIN */ -| error ':' enumerated_spec_init - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for enumerated type declaration."); yyerrok;} -| identifier enumerated_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in enumerated type declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -enumerated_spec_init: - enumerated_specification - {$$ = new enumerated_spec_init_c($1, NULL, locloc(@$));} -| enumerated_specification ASSIGN enumerated_value - {$$ = new enumerated_spec_init_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| enumerated_specification enumerated_value - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in enumerated specification with initialization."); yynerrs++;} -| enumerated_specification ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined in enumerated specification with initialization.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value in enumerated specification with initialization."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -enumerated_specification: - '(' enumerated_value_list ')' - {$$ = $2;} -| prev_declared_enumerated_type_name -/* ERROR_CHECK_BEGIN */ -| '(' ')' - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no enumerated value list defined in enumerated specification."); yynerrs++;} -| '(' error ')' - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid enumerated value list defined in enumerated specification.");yyerrok;} -| '(' enumerated_value_list error - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of enumerated specification."); yyerrok;} -/* ERROR_CHECK_END */ -; - -/* helper symbol for enumerated_specification */ -enumerated_value_list: - enumerated_value - {$$ = new enumerated_value_list_c(locloc(@$)); $$->add_element($1);} -| enumerated_value_list ',' enumerated_value - {$$ = $1; $$->add_element($3);} -/* ERROR_CHECK_BEGIN */ -| enumerated_value_list enumerated_value - {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in enumerated value list.");} -| enumerated_value_list ',' error - {$$ = $1; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined in enumerated value list.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value in enumerated value list."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -enumerated_value: - identifier - {$$ = new enumerated_value_c(NULL, $1, locloc(@$));} -| prev_declared_enumerated_type_name '#' any_identifier - {$$ = new enumerated_value_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| prev_declared_enumerated_type_name any_identifier - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between enumerated type name and value in enumerated literal."); yynerrs++;} -| prev_declared_enumerated_type_name '#' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for enumerated literal.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value for enumerated literal."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -/* -enumerated_value_without_identifier: - prev_declared_enumerated_type_name '#' any_identifier - {$$ = new enumerated_value_c($1, $3, locloc(@$));} -; -*/ - - -array_type_declaration: -/* array_type_name ':' array_spec_init */ - identifier ':' array_spec_init - {$$ = new array_type_declaration_c($1, $3, locloc(@$)); - library_element_symtable.insert($1, prev_declared_array_type_name_token); - } -/* ERROR_CHECK_BEGIN */ -| identifier array_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in array type declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - -array_spec_init: - array_specification - {$$ = new array_spec_init_c($1, NULL, locloc(@$));} -| array_specification ASSIGN array_initialization - {$$ = new array_spec_init_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| array_specification array_initialization - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in array specification with initialization."); yynerrs++;} -| array_specification ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in array specification with initialization.");} - else {print_err_msg(locf(@3), locl(@3), "invalid initial value in array specification with initialization."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -array_specification: - prev_declared_array_type_name -| ARRAY '[' array_subrange_list ']' OF non_generic_type_name - {$$ = new array_specification_c($3, $6, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| ARRAY array_subrange_list ']' OF non_generic_type_name - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'[' missing before subrange list in array specification."); yynerrs++;} -| ARRAY '[' ']' OF non_generic_type_name - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no subrange list defined in array specification."); yynerrs++;} -| ARRAY '[' error ']' OF non_generic_type_name - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid subrange list defined in array specification."); yyerrok;} -| ARRAY OF non_generic_type_name - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no subrange list defined in array specification."); yynerrs++;} -| ARRAY error OF non_generic_type_name - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid subrange list defined in array specification."); yyerrok;} -| ARRAY '[' array_subrange_list OF non_generic_type_name - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "']' missing after subrange list in array specification."); yynerrs++;} -| ARRAY '[' array_subrange_list ']' non_generic_type_name - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "'OF' missing between subrange list and item type name in array specification."); yynerrs++;} -| ARRAY '[' array_subrange_list ']' OF error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no item data type defined in array specification.");} - else {print_err_msg(locf(@3), locl(@3), "invalid item data type in array specification."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -/* helper symbol for array_specification */ -array_subrange_list: - subrange - {$$ = new array_subrange_list_c(locloc(@$)); $$->add_element($1);} -| array_subrange_list ',' subrange - {$$ = $1; $$->add_element($3);} -/* ERROR_CHECK_BEGIN */ -| array_subrange_list subrange - {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in subrange list."); yynerrs++;} -| array_subrange_list ',' error - {$$ = $1; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no subrange defined in subrange list.");} - else {print_err_msg(locf(@3), locl(@3), "invalid subrange in subrange list."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -array_initialization: - '[' array_initial_elements_list ']' - {$$ = $2;} -/* ERROR_CHECK_BEGIN */ -| '[' ']' - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no initial values list defined in array initialization."); yynerrs++;} -| '[' error ']' - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid initial values list defined in array initialization."); yyerrok;} -| '[' array_initial_elements_list error - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "']' missing at the end of array initialization."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -/* helper symbol for array_initialization */ -array_initial_elements_list: - array_initial_elements - {$$ = new array_initial_elements_list_c(locloc(@$)); $$->add_element($1);} -| array_initial_elements_list ',' array_initial_elements - {$$ = $1; $$->add_element($3);} -/* ERROR_CHECK_BEGIN -| array_initial_elements_list ',' error - {$$ = $1; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no array initial value in array initial values list.");} - else {print_err_msg(locf(@3), locl(@3), "invalid array initial value in array initial values list."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -array_initial_elements: - array_initial_element -| integer '(' ')' -| integer '(' array_initial_element ')' - {$$ = new array_initial_elements_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| integer '(' error ')' - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid array initial value in array initial values list."); yyerrok;} -| integer '(' array_initial_element error - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of array initial value in array initial values list."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -array_initial_element: - constant -| enumerated_value -| structure_initialization -| array_initialization -; - - - -structure_type_declaration: -/* structure_type_name ':' structure_specification */ - identifier ':' structure_specification - {$$ = new structure_type_declaration_c($1, $3, locloc(@$)); - library_element_symtable.insert($1, prev_declared_structure_type_name_token); - } -/* ERROR_CHECK_BEGIN */ -| identifier structure_specification - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in structure type declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -structure_specification: - structure_declaration -| initialized_structure -; - - -initialized_structure: - prev_declared_structure_type_name - {$$ = new initialized_structure_c($1, NULL, locloc(@$));} -| prev_declared_structure_type_name ASSIGN structure_initialization - {$$ = new initialized_structure_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| prev_declared_structure_type_name structure_initialization - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in structure specification with initialization."); yynerrs++;} -| prev_declared_structure_type_name ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined in structure specification with initialization.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value in structure specification with initialization."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -structure_declaration: - STRUCT structure_element_declaration_list END_STRUCT - {$$ = $2;} -/* ERROR_CHECK_BEGIN */ -| STRUCT END_STRUCT - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no structure element declared in structure type declaration."); yynerrs++;} -| STRUCT error structure_element_declaration_list END_STRUCT - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'STRUCT' in structure type declaration."); yyerrok;} -| STRUCT structure_element_declaration_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed structure type declaration."); yyerrok;} -| STRUCT error END_STRUCT - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in structure type declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - -/* helper symbol for structure_declaration */ -structure_element_declaration_list: - structure_element_declaration ';' - {$$ = new structure_element_declaration_list_c(locloc(@$)); $$->add_element($1);} -| structure_element_declaration_list structure_element_declaration ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| error ';' - {$$ = new structure_element_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid structure element declaration."); yyerrok;} -| structure_element_declaration error - {$$ = new structure_element_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of structure element declaration."); yyerrok;} -| structure_element_declaration_list structure_element_declaration error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of structure element declaration."); yyerrok;} -| structure_element_declaration_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid structure element declaration."); yyerrok;} -| structure_element_declaration_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after structure element declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -structure_element_declaration: - structure_element_name ':' simple_spec_init - {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} -| structure_element_name ':' subrange_spec_init - {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} -| structure_element_name ':' enumerated_spec_init - {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} -| structure_element_name ':' array_spec_init - {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} -| structure_element_name ':' initialized_structure - {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| structure_element_name simple_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and simple specification."); yynerrs++;} -| structure_element_name subrange_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and subrange specification."); yynerrs++;} -| structure_element_name enumerated_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and enumerated specification."); yynerrs++;} -| structure_element_name array_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and array specification."); yynerrs++;} -| structure_element_name initialized_structure - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and structure specification."); yynerrs++;} -| structure_element_name ':' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in structure element declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid specification in structure element declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -structure_element_name: any_identifier; - - -structure_initialization: - '(' structure_element_initialization_list ')' - {$$ = $2;} -/* ERROR_CHECK_BEGIN */ -| '(' error ')' - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid structure element initialization list in structure initialization."); yyerrok;} -| '(' structure_element_initialization_list error - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "expecting ')' at the end of structure element initialization list in structure initialization."); yyerrok;} -/* ERROR_CHECK_END */ -; - -/* helper symbol for structure_initialization */ -structure_element_initialization_list: - structure_element_initialization - {$$ = new structure_element_initialization_list_c(locloc(@$)); $$->add_element($1);} -| structure_element_initialization_list ',' structure_element_initialization - {$$ = $1; $$->add_element($3);} -/* ERROR_CHECK_BEGIN -| structure_element_initialization_list structure_element_initialization - {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in structure element initialization list in structure initialization."); yynerrs++;} -| structure_element_initialization_list ',' error - {$$ = $1; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no structure element initialization defined in structure initialization.");} - else {print_err_msg(locf(@3), locl(@3), "invalid structure element initialization in structure initialization."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -structure_element_initialization: - structure_element_name ASSIGN constant - {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} -| structure_element_name ASSIGN enumerated_value - {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} -| structure_element_name ASSIGN array_initialization - {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} -| structure_element_name ASSIGN structure_initialization - {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| structure_element_name constant - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in structure element initialization."); yynerrs++;} -| structure_element_name enumerated_value - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in enumerated structure element initialization."); yynerrs++;} -| structure_element_name array_initialization - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in array structure element initialization."); yynerrs++;} -| structure_element_name structure_initialization - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in structured structure element initialization."); yynerrs++;} -| structure_element_name ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in structured structure element initialization.");} - else {print_err_msg(locf(@3), locl(@3), "invalid initial value in structured structure element initialization."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -/* NOTE: in order to remove a reduce/reduce conflict, - * all occurences of string_type_name - * have been replaced with identifier! - */ -/* -string_type_name: identifier; -*/ - -string_type_declaration: -/* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */ - identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init - {$$ = new string_type_declaration_c($1, $3, $4, $5, locloc(@$)); - library_element_symtable.insert($1, prev_declared_string_type_name_token); - } -; - - -/* helper symbol for string_type_declaration */ -string_type_declaration_size: - '[' integer ']' - {$$ = $2;} -/* REMOVED !! */ -//| /* empty */ -// {$$ = NULL;} -; -/* The syntax contains a reduce/reduce conflict. - * The optional '[' ']' - * has been changed to become mandatory to remove the conflict. - * - * The conflict arises because - * new_str_type : STRING := "hello!" - * may be reduced to a string_type_declaration OR - * a simple_type_declaration. - * - * Our change forces it to be reduced to a - * simple_type_declaration! - * We chose this option because changing the definition - * of simple_spec_init would force us to change all the other - * rules in which it appears. The change we made has no - * side-effects! - */ - -/* helper symbol for string_type_declaration */ -string_type_declaration_init: - /* empty */ - {$$ = NULL;} -| ASSIGN character_string - {$$ = $2;} -; - - - -/*********************/ -/* B 1.4 - Variables */ -/*********************/ -/* NOTE: The standard is erroneous in it's definition of 'variable' because: - * - The standard considers 'ENO' as a keyword... - * - ...=> which means that it may never be parsed as an 'identifier'... - * - ...=> and therefore may never be used as the name of a variable inside an expression. - * - However, a function/FB must be able to assign the ENO parameter - * it's value, doing it in an assignment statement, and therefore using the 'ENO' - * character sequence as an identifier! - * The obvious solution is to also allow the ENO keyword to be - * used as the name of a variable. Note that this variable may be used - * even though it is not explicitly declared as a function/FB variable, - * as the standard requires us to define it implicitly in this case! - * There are three ways of achieving this: - * (i) simply not define EN and ENO as keywords in flex (lexical analyser) - * and let them be considered 'identifiers'. Aditionally, add some code - * so that if they are not explicitly declared, we add them automatically to - * the declaration of each Functions and FB, where they would then be parsed - * as a previously_declared_variable. - * This approach has the advantage the EN and ENO would automatically be valid - * in every location where it needs to be valid, namely in the explicit declaration - * of these same variables, or when they are used within expressions. - * However, this approach has the drawback that - * EN and ENO could then also be used anywhere a standard identifier is allowed, - * including in the naming of Functions, FBs, Programs, Configurations, Resources, - * SFC Actions, SFC Steps, etc... - * This would mean that we would then have to add a lexical analysis check - * within the bison code (syntax analyser) to all the above constructs to make sure - * that the identifier being used is not EN or ENO. - * (ii) The other approach is to define EN and ENO as keywords / tokens in flex - * (lexical analyser) and then change the syntax in bison to acomodate - * these tokens wherever they could correctly appear. - * This has the drawback that we need to do some changes to the synax defintion. - * (iii) Yet a another option is to mix the above two methods. - * Define EN and ENO as tokens in flex, but change (only) the syntax for - * variable declaration to allow these tokens to also be used in declaring variables. - * From this point onwards these tokens are then considered a previously_declared_variable, - * since flex will first check for this before even checking for tokens. - * - * I (Mario) cuurretnly (2011) believe the cleanest method of achieving this goal - * is to use option (iii) - * However, considering that: - * - I have already previously implemented option (ii); - * - option (iii) requires that flex parse the previously_declared_variable - * before parsing any token. We already support this (remeber that this is - * used mainly to allow some IL operators as well as PRIORITY, etc. tokens - * to be used as identifiers, since the standard does not define them as keywords), - * but this part of the code in flex is often commented out as usually people do not expect - * us to follow the standard in the strict sense, but rather consider those - * tokens as keywords; - * considering the above, we currently carry on using option (ii). - */ -variable: - symbolic_variable -| prev_declared_direct_variable -| eno_identifier - {$$ = new symbolic_variable_c($1, locloc(@$));} -; - - -symbolic_variable: -/* NOTE: To be entirely correct, variable_name must be replacemed by - * prev_declared_variable_name | prev_declared_fb_name | prev_declared_global_var_name - */ - prev_declared_fb_name - {$$ = new symbolic_variable_c($1, locloc(@$));} -| prev_declared_global_var_name - {$$ = new symbolic_variable_c($1, locloc(@$));} -| prev_declared_variable_name - {$$ = new symbolic_variable_c($1, locloc(@$));} -| multi_element_variable -/* -| identifier - {$$ = new symbolic_variable_c($1, locloc(@$));} -*/ -; - - -/* NOTE: in section B 1.7, when configuring a program, symbolic_variable - * is used. Nevertheless, during the parsing of a configuration, - * the variables in question are out of scope, so we should - * be allowing any_identifier instead of prev_declared_variable_name! - * - * We therefore need a new any_symbolic_variable construct that - * allows the use of any_identifier instead of previously declared - * variables, function blocks, etc... - */ -any_symbolic_variable: -// variable_name -> replaced by any_identifier - any_identifier - {$$ = new symbolic_variable_c($1, locloc(@$));} -| any_multi_element_variable -; - - -/* for yet undeclared variable names ! */ -variable_name: identifier; - - - - - -/********************************************/ -/* B.1.4.1 Directly Represented Variables */ -/********************************************/ -prev_declared_direct_variable: prev_declared_direct_variable_token {$$ = new direct_variable_c($1, locloc(@$));}; - - - - -/*************************************/ -/* B.1.4.2 Multi-element Variables */ -/*************************************/ -multi_element_variable: - array_variable -| structured_variable -; - -/* please see note above any_symbolic_variable */ -any_multi_element_variable: - any_array_variable -| any_structured_variable -; - - -array_variable: - subscripted_variable '[' subscript_list ']' - {$$ = new array_variable_c($1, $3, locloc(@$));} -; - -/* please see note above any_symbolic_variable */ -any_array_variable: - any_subscripted_variable '[' subscript_list ']' - {$$ = new array_variable_c($1, $3, locloc(@$));} -; - - -subscripted_variable: - symbolic_variable -; - - -/* please see note above any_symbolic_variable */ -any_subscripted_variable: - any_symbolic_variable -; - - -subscript_list: - subscript - {$$ = new subscript_list_c(locloc(@$)); $$->add_element($1);} -| subscript_list ',' subscript - {$$ = $1; $$->add_element($3);} -; - - -subscript: expression; - - -structured_variable: - record_variable '.' field_selector - {$$ = new structured_variable_c($1, $3, locloc(@$));} -; - - -/* please see note above any_symbolic_variable */ -any_structured_variable: - any_record_variable '.' field_selector - {$$ = new structured_variable_c($1, $3, locloc(@$));} -; - - - -record_variable: - symbolic_variable -; - - -/* please see note above any_symbolic_variable */ -any_record_variable: - any_symbolic_variable -; - - -field_selector: - any_identifier -| eno_identifier -; - - - - - - -/******************************************/ -/* B 1.4.3 - Declaration & Initialisation */ -/******************************************/ -input_declarations: - VAR_INPUT input_declaration_list END_VAR - {$$ = new input_declarations_c(NULL, $2, new explicit_definition_c(), locloc(@$));} -| VAR_INPUT RETAIN input_declaration_list END_VAR - {$$ = new input_declarations_c(new retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} -| VAR_INPUT NON_RETAIN input_declaration_list END_VAR - {$$ = new input_declarations_c(new non_retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| VAR_INPUT END_VAR - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in input variable(s) declaration."); yynerrs++;} -| VAR_INPUT RETAIN END_VAR - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive input variable(s) declaration."); yynerrs++;} -| VAR_INPUT NON_RETAIN END_VAR - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in non-retentive input variable(s) declaration."); yynerrs++;} -| VAR_INPUT error input_declaration_list END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_INPUT' in input variable(s) declaration."); yyerrok;} -| VAR_INPUT RETAIN error input_declaration_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive input variable(s) declaration."); yyerrok;} -| VAR_INPUT NON_RETAIN error input_declaration_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive input variable(s) declaration."); yyerrok;} -| VAR_INPUT input_declaration_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed input variable(s) declaration."); yyerrok;} -| VAR_INPUT RETAIN input_declaration_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive input variable(s) declaration."); yyerrok;} -| VAR_INPUT NON_RETAIN input_declaration_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed non-retentive input variable(s) declaration."); yyerrok;} -| VAR_INPUT error END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in input variable(s) declaration."); yyerrok;} -| VAR_INPUT RETAIN error END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in retentive input variable(s) declaration."); yyerrok;} -| VAR_INPUT NON_RETAIN error END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in non-retentive input variable(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - -/* helper symbol for input_declarations */ -input_declaration_list: - input_declaration ';' - {$$ = new input_declaration_list_c(locloc(@$)); $$->add_element($1);} -| input_declaration_list input_declaration ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| error ';' - {$$ = new input_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid input variable(s) declaration."); yyerrok;} -| input_declaration error - {$$ = new input_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of input variable(s) declaration."); yyerrok;} -| input_declaration_list input_declaration error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of input variable(s) declaration."); yyerrok;} -| input_declaration_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid input variable(s) declaration."); yyerrok;} -| input_declaration_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after input variable(s) declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -/* NOTE: The formal definition of 'input_declaration' as defined in the standard is erroneous, - * as it does not allow a user defined 'EN' input parameter. However, - * The semantic description of the languages clearly states that this is allowed. - * We have added the 'en_param_declaration' clause to cover for this. - */ -input_declaration: - var_init_decl -| edge_declaration -| en_param_declaration -; - - -edge_declaration: - var1_list ':' BOOL R_EDGE - {$$ = new edge_declaration_c(new raising_edge_option_c(locloc(@3)), $1, locloc(@$));} -| var1_list ':' BOOL F_EDGE - {$$ = new edge_declaration_c(new falling_edge_option_c(locloc(@3)), $1, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| var1_list BOOL R_EDGE - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in edge declaration."); yynerrs++;} -| var1_list BOOL F_EDGE - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in edge declaration."); yynerrs++;} -| var1_list ':' BOOL R_EDGE F_EDGE - {$$ = NULL; print_err_msg(locl(@5), locf(@5), "'R_EDGE' and 'F_EDGE' can't be present at the same time in edge declaration."); yynerrs++;} -| var1_list ':' BOOL F_EDGE R_EDGE - {$$ = NULL; print_err_msg(locl(@5), locf(@5), "'R_EDGE' and 'F_EDGE' can't be present at the same time in edge declaration."); yynerrs++;} -| var1_list ':' R_EDGE - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in edge declaration."); yynerrs++;} -| var1_list ':' F_EDGE - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in edge declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -/* NOTE: The formal definition of the standard is erroneous, as it simply does not - * consider the EN and ENO keywords! - * The semantic description of the languages clearly states that these may be - * used in several ways. One of them is to declare an EN input parameter. - * We have added the 'en_param_declaration' clause to cover for this. - * - * Please read the comment above the definition of 'variable' in section B1.4 for details. - */ -en_param_declaration: - en_identifier ':' BOOL ASSIGN boolean_literal - {$$ = new en_param_declaration_c($1, new bool_type_name_c(locloc(@$)), $5, new explicit_definition_c(), locloc(@$));} -| en_identifier ':' BOOL ASSIGN integer - {$$ = new en_param_declaration_c($1, new bool_type_name_c(locloc(@$)), $5, new explicit_definition_c(), locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| en_identifier BOOL ASSIGN boolean_literal - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in EN declaration."); yynerrs++;} -| en_identifier BOOL ASSIGN integer - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in EN declaration."); yynerrs++;} -| en_identifier ':' ASSIGN boolean_literal - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in EN declaration."); yynerrs++;} -| en_identifier ':' ASSIGN integer - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in EN declaration."); yynerrs++;} -| en_identifier ':' BOOL ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in EN declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid specification in EN declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -var_init_decl: - var1_init_decl -| array_var_init_decl -| structured_var_init_decl -| fb_name_decl -| string_var_declaration -; - - - - -var1_init_decl: - var1_list ':' simple_spec_init - {$$ = new var1_init_decl_c($1, $3, locloc(@$));} -| var1_list ':' subrange_spec_init - {$$ = new var1_init_decl_c($1, $3, locloc(@$));} -| var1_list ':' enumerated_spec_init - {$$ = new var1_init_decl_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| var1_list simple_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and simple specification."); yynerrs++;} -| var1_list subrange_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and subrange specification."); yynerrs++;} -| var1_list enumerated_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and enumerated specification."); yynerrs++;} -| var1_list ':' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in variable declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid specification in variable declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -/* NOTE: - * The syntax - * variable_name DOTDOT - * is an extension to the standard!!! - * - * In order to be able to handle extensible standard functions - * (i.e. standard functions that may have a variable number of - * input parameters, such as AND(word#33, word#44, word#55, word#66), - * we have extended the acceptable syntax to allow var_name '..' - * in an input variable declaration. - * - * This allows us to parse the declaration of standard - * extensible functions and load their interface definition - * into the abstract syntax tree just like we do to other - * user defined functions. - * This has the advantage that we can later do semantic - * checking of calls to functions (be it a standard or user defined - * function) in (almost) exactly the same way. - * - * Of course, we have a flag that disables this syntax when parsing user - * written code, so we only allow this extra syntax while parsing the - * 'header' file that declares all the standard IEC 61131-3 functions. - */ -var1_list: - variable_name - {$$ = new var1_list_c(locloc(@$)); $$->add_element($1); - variable_name_symtable.insert($1, prev_declared_variable_name_token); - } -| variable_name integer DOTDOT - {$$ = new var1_list_c(locloc(@$)); $$->add_element(new extensible_input_parameter_c($1, $2, locloc(@$))); - variable_name_symtable.insert($1, prev_declared_variable_name_token); - if (!allow_extensible_function_parameters) print_err_msg(locf(@1), locl(@2), "invalid syntax in variable name declaration."); - } - | var1_list ',' variable_name - {$$ = $1; $$->add_element($3); - variable_name_symtable.insert($3, prev_declared_variable_name_token); - } - | var1_list ',' variable_name integer DOTDOT - {$$ = $1; $$->add_element(new extensible_input_parameter_c($3, $4, locloc(@$))); - variable_name_symtable.insert($3, prev_declared_variable_name_token); - if (!allow_extensible_function_parameters) print_err_msg(locf(@1), locl(@2), "invalid syntax in variable name declaration."); - } -/* ERROR_CHECK_BEGIN */ -| var1_list variable_name - {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in variable list."); yynerrs++;} -| var1_list ',' error - {$$ = $1; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no variable name defined in variable declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid variable name in variable declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - - -array_var_init_decl: - var1_list ':' array_spec_init - {$$ = new array_var_init_decl_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| var1_list array_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and array specification."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -structured_var_init_decl: - var1_list ':' initialized_structure - {$$ = new structured_var_init_decl_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| var1_list initialized_structure - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and structured specification."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -/* NOTE: see notes above fb_name_list and var1_list - * for reason why ':' was removed from this rule! - * In essence, to remove a shift/reduce conflict, - * the ':' was moved to var1_list and fb_name_list! - */ -fb_name_decl: -/* fb_name_list ':' function_block_type_name */ - fb_name_list_with_colon function_block_type_name - {$$ = new fb_name_decl_c($1, $2, NULL, locloc(@$));} -/*| fb_name_list ':' function_block_type_name ASSIGN structure_initialization */ -| fb_name_list_with_colon function_block_type_name ASSIGN structure_initialization - {$$ = new fb_name_decl_c($1, $2, $4, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| fb_name_list_with_colon ASSIGN structure_initialization - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block type name defined in function block declaration with initialization."); yynerrs++;} -| fb_name_list_with_colon function_block_type_name structure_initialization - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':=' missing in function block declaration with initialization."); yynerrs++;} -| fb_name_list_with_colon function_block_type_name ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no initialization defined in function block declaration.");} - else {print_err_msg(locf(@4), locl(@4), "invalid initialization in function block declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - - -/* NOTE: In order to remove a reduce/reduce conflict between - * var1_list and fb_name_list, which are identical to each - * other, fb_name_list has been redefined to be a var1_list. - * - * In order to remove a further shift/reduce conflict, var1_list - * is imediately transfomred into var1_list_with_colon - * (i.e. it includes the ':' following the list), which - * means that fb_name_list is built from a - * var1_list_with_colon after all! - */ -/* -fb_name_list: - (* fb_name *) - identifier - {$$ = new fb_name_list_c($1); - variable_name_symtable.insert($1, prev_declared_fb_name_token); - } -(* | fb_name_list ',' fb_name *) -| fb_name_list ',' identifier - {$$ = $1; $$->add_element($3); - variable_name_symtable.insert($3, prev_declared_fb_name_token); - } -; -*/ - -fb_name_list_with_colon: - var1_list_with_colon - {$$ = new fb_name_list_c(locloc(@$)); - /* fill up the new fb_name_list_c object with the references - * contained in the var1_list_c object. - */ - FOR_EACH_ELEMENT(elem, $1, {$$->add_element(elem);}); - delete $1; - /* change the tokens associated with the symbols stored in - * the variable name symbol table from prev_declared_variable_name_token - * to prev_declared_fb_name_token - */ - FOR_EACH_ELEMENT(elem, $$, {variable_name_symtable.set(elem, prev_declared_fb_name_token);}); - } -; - -/* helper symbol for fb_name_list_with_colon */ -var1_list_with_colon: - var1_list ':' -; - - -// fb_name: identifier; - - - -output_declarations: - VAR_OUTPUT var_output_init_decl_list END_VAR - {$$ = new output_declarations_c(NULL, $2, new explicit_definition_c(), locloc(@$));} -| VAR_OUTPUT RETAIN var_output_init_decl_list END_VAR - {$$ = new output_declarations_c(new retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} -| VAR_OUTPUT NON_RETAIN var_output_init_decl_list END_VAR - {$$ = new output_declarations_c(new non_retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| VAR_OUTPUT END_VAR - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in output variable(s) declaration."); yynerrs++;} -| VAR_OUTPUT RETAIN END_VAR - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive output variable(s) declaration."); yynerrs++;} -| VAR_OUTPUT NON_RETAIN END_VAR - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in non-retentive output variable(s) declaration."); yynerrs++;} -| VAR_OUTPUT error var_output_init_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_OUPUT' in output variable(s) declaration."); yyerrok;} -| VAR_OUTPUT RETAIN error var_output_init_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive output variable(s) declaration."); yyerrok;} -| VAR_OUTPUT NON_RETAIN error var_output_init_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive output variable(s) declaration."); yyerrok;} -| VAR_OUTPUT var_output_init_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed output variable(s) declaration."); yyerrok;} -| VAR_OUTPUT RETAIN var_output_init_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive output variable(s) declaration."); yyerrok;} -| VAR_OUTPUT NON_RETAIN var_output_init_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed non-retentive output variable(s) declaration."); yyerrok;} -| VAR_OUTPUT error END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in output variable(s) declaration."); yyerrok;} -| VAR_OUTPUT RETAIN error END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in retentive output variable(s) declaration."); yyerrok;} -| VAR_OUTPUT NON_RETAIN error END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in non-retentive output variable(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -/* NOTE: The formal definition of 'var_output_init_decl' as defined in the standard is erroneous, - * as it does not allow a user defined 'ENO' output parameter. However, - * The semantic description of the languages clearly states that this is allowed. - * We have added the 'eno_param_declaration' clause to cover for this. - * - * Please read the comment above the definition of 'variable' in section B1.4 for details. - */ -var_output_init_decl: - var_init_decl -| eno_param_declaration -; - -var_output_init_decl_list: - var_output_init_decl ';' - {$$ = new var_init_decl_list_c(locloc(@$)); $$->add_element($1);} -| var_output_init_decl_list var_output_init_decl ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| var_output_init_decl_list var_output_init_decl error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of variable(s) declaration."); yyerrok;} -| var_output_init_decl_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid variable(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -/* NOTE: The formal definition of the standard is erroneous, as it simply does not - * consider the EN and ENO keywords! - * The semantic description of the languages clearly states that these may be - * used in several ways. One of them is to declare an ENO output parameter. - * We have added the 'eno_param_declaration' clause to cover for this. - * - * Please read the comment above the definition of 'variable' in section B1.4 for details. - */ -eno_param_declaration: - eno_identifier ':' BOOL - /* NOTE We do _NOT_ include this variable in the previously_declared_variable symbol table! - * Please read the comment above the definition of 'variable' for the reason for this. - */ - {$$ = new eno_param_declaration_c($1, new bool_type_name_c(locloc(@$)), new explicit_definition_c(), locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| eno_identifier BOOL - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in ENO declaration."); yynerrs++;} -| eno_identifier ':' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in ENO declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid specification in ENO declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -input_output_declarations: - VAR_IN_OUT var_declaration_list END_VAR - {$$ = new input_output_declarations_c($2, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| VAR_IN_OUT END_VAR - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in in_out variable(s) declaration."); yynerrs++;} -| VAR_IN_OUT error var_declaration_list END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_IN_OUT' in in_out variable(s) declaration."); yyerrok;} -| VAR_IN_OUT var_declaration_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed in_out variable(s) declaration."); yyerrok;} -| VAR_IN_OUT error END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in in_out variable(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - - -/* helper symbol for input_output_declarations */ -var_declaration_list: - var_declaration ';' - {$$ = new var_declaration_list_c(locloc(@$)); $$->add_element($1);} -| var_declaration_list var_declaration ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| error ';' - {$$ = new var_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid variable(s) declaration."); yyerrok;} -| var_declaration error - {$$ = new var_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of variable(s) declaration."); yyerrok;} -| var_declaration_list var_declaration error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of variable(s) declaration."); yyerrok;} -| var_declaration_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid variable(s) declaration."); yyerrok;} -| var_declaration_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after variable(s) declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -var_declaration: - temp_var_decl -| fb_name_decl -; - - -temp_var_decl: - var1_declaration -| array_var_declaration -| structured_var_declaration -| string_var_declaration -; - -var1_declaration: - var1_list ':' simple_specification - {$$ = new var1_init_decl_c($1, $3, locloc(@$));} -| var1_list ':' subrange_specification - {$$ = new var1_init_decl_c($1, $3, locloc(@$));} -| var1_list ':' enumerated_specification - {$$ = new var1_init_decl_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| var1_list simple_specification - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and simple specification."); yynerrs++;} -| var1_list subrange_specification - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and subrange specification."); yynerrs++;} -| var1_list enumerated_specification - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and enumerated specification."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - - -array_var_declaration: - var1_list ':' array_specification - {$$ = new array_var_declaration_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| var1_list array_specification - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and array specification."); yynerrs++;} -/* ERROR_CHECK_END */ -; - -structured_var_declaration: - var1_list ':' prev_declared_structure_type_name - {$$ = new structured_var_declaration_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| var1_list prev_declared_structure_type_name - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and structured specification."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -var_declarations: - VAR var_init_decl_list END_VAR - {$$ = new var_declarations_c(NULL, $2, locloc(@$));} -| VAR CONSTANT var_init_decl_list END_VAR - {$$ = new var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| VAR END_VAR - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in variable(s) declaration."); yynerrs++;} -| VAR CONSTANT END_VAR - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in constant variable(s) declaration."); yynerrs++;} -| VAR error var_init_decl_list END_VAR - {$$ = NULL; print_err_msg(locl(@1), locf(@3), "unexpected token after 'VAR' in variable(s) declaration."); yyerrok;} -| VAR CONSTANT error var_init_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant variable(s) declaration."); yyerrok;} -| VAR var_init_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed variable(s) declaration."); yyerrok;} -| VAR CONSTANT var_init_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant variable(s) declaration."); yyerrok;} -| VAR error END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in variable(s) declaration."); yyerrok;} -| VAR CONSTANT error END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant variable(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -retentive_var_declarations: - VAR RETAIN var_init_decl_list END_VAR - {$$ = new retentive_var_declarations_c($3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| VAR RETAIN END_VAR - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive variable(s) declaration."); yynerrs++;} -| VAR RETAIN error var_init_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive variable(s) declaration."); yyerrok;} -| VAR RETAIN var_init_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive variable(s) declaration."); yyerrok;} -| VAR RETAIN error END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in retentive variable(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -located_var_declarations: - VAR located_var_decl_list END_VAR - {$$ = new located_var_declarations_c(NULL, $2, locloc(@$));} -| VAR CONSTANT located_var_decl_list END_VAR - {$$ = new located_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} -| VAR RETAIN located_var_decl_list END_VAR - {$$ = new located_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));} -| VAR NON_RETAIN located_var_decl_list END_VAR - {$$ = new located_var_declarations_c(new non_retain_option_c(locloc(@2)), $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| VAR NON_RETAIN END_VAR - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in non-retentive located variable(s) declaration."); yynerrs++;} -| VAR error located_var_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR' in located variable(s) declaration."); yyerrok;} -| VAR CONSTANT error located_var_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant located variable(s) declaration."); yyerrok;} -| VAR RETAIN error located_var_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive located variable(s) declaration."); yyerrok;} -| VAR NON_RETAIN error located_var_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive located variable(s) declaration."); yyerrok;} -| VAR located_var_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed located variable(s) declaration."); yyerrok;} -| VAR CONSTANT located_var_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant located variable(s) declaration."); yyerrok;} -| VAR RETAIN located_var_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive located variable(s) declaration."); yyerrok;} -| VAR NON_RETAIN located_var_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed non-retentive located variable(s) declaration."); yyerrok;} -| VAR NON_RETAIN error END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in non retentive variable(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -/* helper symbol for located_var_declarations */ -located_var_decl_list: - located_var_decl ';' - {$$ = new located_var_decl_list_c(locloc(@$)); $$->add_element($1);} -| located_var_decl_list located_var_decl ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| error ';' - {$$ = new located_var_decl_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid located variable declaration."); yyerrok;} -| located_var_decl error - {$$ = new located_var_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of located variable declaration."); yyerrok;} -| located_var_decl_list located_var_decl error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of located variable declaration."); yyerrok;} -| located_var_decl_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid located variable declaration."); yyerrok;} -| located_var_decl_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after located variable declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -located_var_decl: - variable_name location ':' located_var_spec_init - {$$ = new located_var_decl_c($1, $2, $4, locloc(@$)); - variable_name_symtable.insert($1, prev_declared_variable_name_token); - } -| location ':' located_var_spec_init - {$$ = new located_var_decl_c(NULL, $1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| variable_name location located_var_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between located variable location and specification."); yynerrs++;} -| location located_var_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between located variable location and specification."); yynerrs++;} -| variable_name location ':' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in located variable declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid specification in located variable declaration."); yyclearin;} - yyerrok; - } -| location ':' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in located variable declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid specification in located variable declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - - - -external_var_declarations: - VAR_EXTERNAL external_declaration_list END_VAR - {$$ = new external_var_declarations_c(NULL, $2, locloc(@$));} -| VAR_EXTERNAL CONSTANT external_declaration_list END_VAR - {$$ = new external_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| VAR_EXTERNAL END_VAR - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in external variable(s) declaration."); yynerrs++;} -| VAR_EXTERNAL CONSTANT END_VAR - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in constant external variable(s) declaration."); yynerrs++;} -| VAR_EXTERNAL error external_declaration_list END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_EXTERNAL' in external variable(s) declaration."); yyerrok;} -| VAR_EXTERNAL CONSTANT error external_declaration_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant external variable(s) declaration."); yyerrok;} -| VAR_EXTERNAL external_declaration_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed external variable(s) declaration."); yyerrok;} -| VAR_EXTERNAL CONSTANT external_declaration_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant external variable(s) declaration."); yyerrok;} -| VAR_EXTERNAL error END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in external variable(s) declaration."); yyerrok;} -| VAR_EXTERNAL CONSTANT error END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant external variable(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - -/* helper symbol for external_var_declarations */ -external_declaration_list: - external_declaration ';' - {$$ = new external_declaration_list_c(locloc(@$)); $$->add_element($1);} -| external_declaration_list external_declaration ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| error ';' - {$$ = new external_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid external variable declaration."); yyerrok;} -| external_declaration error - {$$ = new external_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of external variable declaration."); yyerrok;} -| external_declaration_list external_declaration error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of external variable declaration."); yyerrok;} -| external_declaration_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid external variable declaration."); yyerrok;} -| external_declaration_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after external variable declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -external_declaration: - global_var_name ':' simple_specification - {$$ = new external_declaration_c($1, $3, locloc(@$)); - variable_name_symtable.insert($1, prev_declared_variable_name_token); - } -| global_var_name ':' subrange_specification - {$$ = new external_declaration_c($1, $3, locloc(@$)); - variable_name_symtable.insert($1, prev_declared_variable_name_token); - } -| global_var_name ':' enumerated_specification - {$$ = new external_declaration_c($1, $3, locloc(@$)); - variable_name_symtable.insert($1, prev_declared_variable_name_token); - } -| global_var_name ':' array_specification - {$$ = new external_declaration_c($1, $3, locloc(@$)); - variable_name_symtable.insert($1, prev_declared_variable_name_token); - } -| global_var_name ':' prev_declared_structure_type_name - {$$ = new external_declaration_c($1, $3, locloc(@$)); - variable_name_symtable.insert($1, prev_declared_variable_name_token); - } -| global_var_name ':' function_block_type_name - {$$ = new external_declaration_c($1, $3, locloc(@$)); - variable_name_symtable.insert($1, prev_declared_fb_name_token); - } -/* ERROR_CHECK_BEGIN */ -| global_var_name simple_specification - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and simple specification."); yynerrs++;} -| global_var_name subrange_specification - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and subrange specification."); yynerrs++;} -| global_var_name enumerated_specification - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and enumerated specification."); yynerrs++;} -| global_var_name array_specification - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and array specification."); yynerrs++;} -| global_var_name prev_declared_structure_type_name - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and structured specification."); yynerrs++;} -| global_var_name function_block_type_name - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and function block type specification."); yynerrs++;} -| global_var_name ':' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in external variable declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid specification in external variable declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -global_var_name: identifier; - - -global_var_declarations: - VAR_GLOBAL global_var_decl_list END_VAR - {$$ = new global_var_declarations_c(NULL, $2, locloc(@$));} -| VAR_GLOBAL CONSTANT global_var_decl_list END_VAR - {$$ = new global_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} -| VAR_GLOBAL RETAIN global_var_decl_list END_VAR - {$$ = new global_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| VAR_GLOBAL END_VAR - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in global variable(s) declaration."); yynerrs++;} -| VAR_GLOBAL CONSTANT END_VAR - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in constant global variable(s) declaration."); yynerrs++;} -| VAR_GLOBAL RETAIN END_VAR - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive global variable(s) declaration."); yynerrs++;} -| VAR_GLOBAL error global_var_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_GLOBAL' in global variable(s) declaration."); yyerrok;} -| VAR_GLOBAL CONSTANT error global_var_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant global variable(s) declaration."); yyerrok;} -| VAR_GLOBAL RETAIN error global_var_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive global variable(s) declaration."); yyerrok;} -| VAR_GLOBAL global_var_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed global variable(s) declaration."); yyerrok;} -| VAR_GLOBAL CONSTANT global_var_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant global variable(s) declaration."); yyerrok;} -| VAR_GLOBAL RETAIN global_var_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive global variable(s) declaration."); yyerrok;} -| VAR_GLOBAL error END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in global variable(s) declaration."); yyerrok;} -| VAR_GLOBAL CONSTANT error END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant global variable(s) declaration."); yyerrok;} -| VAR_GLOBAL RETAIN error END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant global variable(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -/* helper symbol for global_var_declarations */ -global_var_decl_list: - global_var_decl ';' - {$$ = new global_var_decl_list_c(locloc(@$)); $$->add_element($1);} -| global_var_decl_list global_var_decl ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| error ';' - {$$ = new global_var_decl_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid global variable(s) declaration."); yyerrok;} -| global_var_decl error - {$$ = new global_var_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of global variable(s) declaration."); yyerrok;} -| global_var_decl_list global_var_decl error - {$$ = $1; print_err_msg(locl(@1), locf(@2), "';' missing at end of global variable(s) declaration."); yyerrok;} -| global_var_decl_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid global variable(s) declaration."); yyerrok;} -| global_var_decl_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after global variable(s) declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -global_var_decl: -/* NOTE : This possibility defined in standard has no sense and generate a conflict (disabled) - global_var_spec ':' - {$$ = new global_var_decl_c($1, NULL, locloc(@$));} -*/ - global_var_spec ':' located_var_spec_init - {$$ = new global_var_decl_c($1, $3, locloc(@$));} -| global_var_spec ':' function_block_type_name - {$$ = new global_var_decl_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| global_var_list located_var_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between global variable list and type specification."); yynerrs++;} -| global_var_name location located_var_spec_init - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between global variable specification and type specification."); yynerrs++;} -| global_var_spec function_block_type_name - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between global variable specification and function block type specification."); yynerrs++;} -| global_var_spec ':' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in global variable declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid specification in global variable declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -global_var_spec: - global_var_list {$$ = $1;} -| location - {$$ = new global_var_spec_c(NULL, $1, locloc(@$));} -| global_var_name location - {$$ = new global_var_spec_c($1, $2, locloc(@$)); - variable_name_symtable.insert($1, prev_declared_global_var_name_token); - } -; - - -located_var_spec_init: - simple_spec_init -| subrange_spec_init -| enumerated_spec_init -| array_spec_init -| initialized_structure -| single_byte_string_spec -| double_byte_string_spec -; - - -location: - AT direct_variable_token - {$$ = new location_c(new direct_variable_c($2, locloc(@$)), locloc(@$)); - direct_variable_symtable.insert($2, prev_declared_direct_variable_token); - } -/* ERROR_CHECK_BEGIN */ -| AT error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no location defined in location declaration.");} - else {print_err_msg(locf(@2), locl(@2), "invalid location in global location declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - - -global_var_list: - global_var_name - {$$ = new global_var_list_c(locloc(@$)); $$->add_element($1); - variable_name_symtable.insert($1, prev_declared_global_var_name_token); - } -| global_var_list ',' global_var_name - {$$ = $1; $$->add_element($3); - variable_name_symtable.insert($3, prev_declared_global_var_name_token); - } -/* ERROR_CHECK_BEGIN */ -| global_var_list global_var_name - {$$ = new global_var_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "',' missing in global variable list."); yynerrs++;} -| global_var_list ',' error - {$$ = $1; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no variable name defined in global variable declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid variable name in global variable declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - - -string_var_declaration: - single_byte_string_var_declaration -| double_byte_string_var_declaration -; - -single_byte_string_var_declaration: - var1_list ':' single_byte_string_spec - {$$ = new single_byte_string_var_declaration_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| var1_list single_byte_string_spec - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and string type specification."); yynerrs++;} -/* ERROR_CHECK_END */ -; - -/* NOTE: The constructs - * - * [W]STRING - * and - * [W]STRING ASSIGN single_byte_character_string - * - * were removed as they are already contained - * within a other constructs. - * - * single_byte_string_spec is used in: - * - single_byte_string_var_declaration -> - * -> string_var_declaration ---> var_init_decl - * |--> temp_var_decl - * |--> var2_init_decl - * - located_var_spec_init - * - * STRING [ASSIGN string_constant] -> elementary_string_type_name -> - * -> simple_spec -> simple_specification -> simple_spec_init -> - * -> located_var_spec_init - * - * STRING [ASSIGN string_constant] -> elementary_string_type_name -> - * -> simple_spec -> simple_specification -> simple_spec_init -> - * -> var1_init_decl -> var_init_decl - * - * STRING [ASSIGN string_constant] -> elementary_string_type_name -> - * -> simple_spec -> simple_specification -> simple_spec_init -> - * -> var1_init_decl -> var2_init_decl - * - * STRING [ASSIGN string_constant] -> elementary_string_type_name -> - * -> simple_spec -> simple_specification -> - * -> var1_declaration -> temp_var_decl - */ -single_byte_string_spec: -/* STRING - {$$ = new single_byte_string_spec_c(NULL, NULL);} -*/ - STRING '[' integer ']' - {$$ = new single_byte_string_spec_c(new single_byte_limited_len_string_spec_c(new string_type_name_c(locloc(@1)), $3, locloc(@$)), NULL, locloc(@$));} -/* -| STRING ASSIGN single_byte_character_string - {$$ = new single_byte_string_spec_c($1, NULL, $3, locloc(@$));} -*/ -| STRING '[' integer ']' ASSIGN single_byte_character_string - {$$ = new single_byte_string_spec_c(new single_byte_limited_len_string_spec_c(new string_type_name_c(locloc(@1)), $3, locloc(@$)), $6, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| STRING '[' error ']' - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited string type specification."); yyerrok;} -| STRING '[' error ']' ASSIGN single_byte_character_string - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited string type specification."); yyerrok;} -| STRING '[' ']' - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited string type specification."); yynerrs++;} -| STRING '[' ']' ASSIGN single_byte_character_string - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited string type specification."); yynerrs++;} -| STRING '[' integer error - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "expecting ']' after length definition for limited string type specification."); yyerrok;} -| STRING '[' integer ']' single_byte_character_string - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':=' missing before limited string type initialization."); yynerrs++;} -| STRING '[' integer ']' ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@5), locf(@6), "no initial value defined in limited string type initialization.");} - else {print_err_msg(locf(@6), locl(@6), "invalid initial value in limited string type initialization."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -double_byte_string_var_declaration: - var1_list ':' double_byte_string_spec - {$$ = new double_byte_string_var_declaration_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| var1_list double_byte_string_spec - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and double byte string type specification."); yynerrs++;} -/* ERROR_CHECK_END */ -; - -double_byte_string_spec: -/* WSTRING - {$$ = new double_byte_string_spec_c($1, NULL, NULL, locloc(@$));} -*/ - WSTRING '[' integer ']' - {$$ = new double_byte_string_spec_c(new double_byte_limited_len_string_spec_c(new wstring_type_name_c(locloc(@1)), $3, locloc(@$)), NULL, locloc(@$));} - -/* -| WSTRING ASSIGN double_byte_character_string - {$$ = new double_byte_string_spec_c($1, NULL, $3, locloc(@$));} -*/ -| WSTRING '[' integer ']' ASSIGN double_byte_character_string - {$$ = new double_byte_string_spec_c(new double_byte_limited_len_string_spec_c(new wstring_type_name_c(locloc(@1)), $3, locloc(@$)), $6, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| WSTRING '[' error ']' - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited double byte string type specification."); yyerrok;} -| WSTRING '[' error ']' ASSIGN single_byte_character_string - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited double byte string type specification."); yyerrok;} -| WSTRING '[' ']' - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited double byte string type specification."); yynerrs++;} -| WSTRING '[' ']' ASSIGN single_byte_character_string - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited double byte string type specification."); yynerrs++;} -| WSTRING '[' integer error - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "expecting ']' after length definition for limited double byte string type specification."); yyerrok;} -| WSTRING '[' integer ']' single_byte_character_string - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':=' missing before limited double byte string type initialization."); yynerrs++;} -| WSTRING '[' integer ']' ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@5), locf(@6), "no initial value defined double byte in limited string type initialization.");} - else {print_err_msg(locf(@6), locl(@6), "invalid initial value in limited double byte string type initialization."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - - -incompl_located_var_declarations: - VAR incompl_located_var_decl_list END_VAR - {$$ = new incompl_located_var_declarations_c(NULL, $2, locloc(@$));} -| VAR RETAIN incompl_located_var_decl_list END_VAR - {$$ = new incompl_located_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));} -| VAR NON_RETAIN incompl_located_var_decl_list END_VAR - {$$ = new incompl_located_var_declarations_c(new non_retain_option_c(locloc(@2)), $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| VAR incompl_located_var_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed incomplete located variable(s) declaration."); yyerrok;} -| VAR RETAIN incompl_located_var_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed incomplete retentive located variable(s) declaration."); yyerrok;} -| VAR NON_RETAIN incompl_located_var_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed incomplete non-retentive located variable(s) declaration."); yyerrok;} -| VAR error incompl_located_var_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR' in incomplete located variable(s) declaration."); yyerrok;} -| VAR RETAIN error incompl_located_var_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive located variable(s) declaration."); yyerrok;} -| VAR NON_RETAIN error incompl_located_var_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive located variable(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - -/* helper symbol for incompl_located_var_declarations */ -incompl_located_var_decl_list: - incompl_located_var_decl ';' - {$$ = new incompl_located_var_decl_list_c(locloc(@$)); $$->add_element($1);} -| incompl_located_var_decl_list incompl_located_var_decl ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| incompl_located_var_decl error - {$$ = new incompl_located_var_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of incomplete located variable declaration."); yyerrok;} -| incompl_located_var_decl_list incompl_located_var_decl error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of incomplete located variable declaration."); yyerrok;} -| incompl_located_var_decl_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid incomplete located variable declaration."); yyerrok;} -| incompl_located_var_decl_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after incomplete located variable declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -incompl_located_var_decl: - variable_name incompl_location ':' var_spec - {$$ = new incompl_located_var_decl_c($1, $2, $4, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| variable_name incompl_location var_spec - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between incomplete located variable and type specification."); yynerrs++; - } -| variable_name incompl_location ':' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in incomplete located variable declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid specification in incomplete located variable declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -incompl_location: - AT incompl_location_token - {$$ = new incompl_location_c($2, locloc(@$));} -; - - -var_spec: - simple_specification -| subrange_specification -| enumerated_specification -| array_specification -| prev_declared_structure_type_name -| string_spec -; - - -/* helper symbol for var_spec */ -string_spec: -/* STRING - {$$ = new single_byte_limited_len_string_spec_c($1, NULL, locloc(@$));} -*/ - STRING '[' integer ']' - {$$ = new single_byte_limited_len_string_spec_c(new string_type_name_c(locloc(@1)), $3, locloc(@$));} -/* -| WSTRING - {$$ = new double_byte_limited_len_string_spec_c($1, NULL, locloc(@$));} -*/ -| WSTRING '[' integer ']' - {$$ = new double_byte_limited_len_string_spec_c(new wstring_type_name_c(locloc(@1)), $3, locloc(@$));} -; - - - - -/* intermediate helper symbol for: - * - non_retentive_var_decls - * - var_declarations - */ -var_init_decl_list: - var_init_decl ';' - {$$ = new var_init_decl_list_c(locloc(@$)); $$->add_element($1);} -| var_init_decl_list var_init_decl ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| var_init_decl_list var_init_decl error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of variable(s) declaration."); yyerrok;} -| var_init_decl_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid variable(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - - - -/***********************/ -/* B 1.5.1 - Functions */ -/***********************/ -/* -function_name: - prev_declared_derived_function_name -| standard_function_name -; -*/ - -/* The following rules should be set such as: - * function_name: function_name_no_clashes | function_name_simpleop_clashes | function_name_expression_clashes - * function_name: function_name_no_NOT_clashes | function_name_NOT_clashes; - */ - -function_name_no_clashes: prev_declared_derived_function_name | standard_function_name_no_clashes; -function_name_simpleop_clashes: standard_function_name_simpleop_clashes; -//function_name_expression_clashes: standard_function_name_expression_clashes; - -function_name_no_NOT_clashes: prev_declared_derived_function_name | standard_function_name_no_NOT_clashes; -//function_name_NOT_clashes: standard_function_name_NOT_clashes; - - -/* NOTE: The list of standard function names - * includes the standard functions MOD(), NOT() - * - * Strangely enough, MOD and NOT are reserved keywords, - * so shouldn't be used for function names. - * - * The specification contradicts itself! - * Our workaround is to treat MOD as a token, - * but to include this token as a - * standard_function_name. - * - * The names of all other standard functions get - * preloaded into the library_element_symbol_table - * with the token value of - * standard_function_name_token - * Actually, simply for completeness, MOD is also - * loaded into the library_element_symbol_table, but - * it is irrelevant since flex will catch MOD as a - * token, before it interprets it as an identifier, - * and looks in the library_element_symbol_table to check - * whether it has been previously declared. - * - * NOTE: The same as the above also occurs with the IL - * operators NOT AND OR XOR ADD SUB MUL DIV MOD - * GT GE EQ LT LE NE. - * Note that MOD is once again in the list! - * Anyway, we give these the same treatement as - * MOD, since we are writing a parser for ST and - * IL simultaneously. If this were not the case, - * the ST parser would not need the tokens NOT AND ... - * - * NOTE: Note that 'NOT' is special, as it conflicts - * with two operators: the IL 'NOT' operator, and - * the unary operator 'NOT' in ST!! - * - * NOTE: The IL language is ambiguous, since using NOT, AND, ... - * may be interpreted as either an IL operator, or - * as a standard function call! - * I (Mario) opted to interpret it as an IL operator. - * This requires changing the syntax for IL language - * function calling, to exclude all function with - * names that clash with IL operators. I therefore - * created the constructs - * function_name_without_clashes - * standard_function_name_without_clashes - * to include all function names, except those that clash - * with IL operators. These constructs are only used - * within the IL language! - */ -/* The following rules should be set such as: - * standard_function_name: standard_function_name_no_clashes | standard_function_name_simpleop_clashes | standard_function_name_expression_clashes - * standard_function_name: standard_function_name_no_NOT_clashes | standard_function_name_NOT_clashes; - */ - -/* -standard_function_name: - standard_function_name_no_clashes -| standard_function_name_expression_clashes -| standard_function_name_NOT_clashes -//| standard_function_name_simpleop_only_clashes -; -*/ - -standard_function_name_no_NOT_clashes: - standard_function_name_no_clashes -| standard_function_name_expression_clashes -//| standard_function_name_simpleop_only_clashes -; - -standard_function_name_no_clashes: - standard_function_name_token - {$$ = new identifier_c($1, locloc(@$));} -; - - -standard_function_name_simpleop_clashes: - standard_function_name_NOT_clashes -//| standard_function_name_simpleop_only_clashes -; - -standard_function_name_NOT_clashes: - NOT - {$$ = new identifier_c(strdup("NOT"), locloc(@$));} -; - -/* Add here any other IL simple operators that collide - * with standard function names! - * Don't forget to uncomment the equivalent lines in - * - standard_function_name_simpleop_clashes - * - standard_function_name - * - standard_function_name_no_NOT_clashes - */ -/* -standard_function_name_simpleop_only_clashes: -; -*/ - -standard_function_name_expression_clashes: - AND {$$ = new identifier_c(strdup("AND"), locloc(@$));} -| OR {$$ = new identifier_c(strdup("OR"), locloc(@$));} -| XOR {$$ = new identifier_c(strdup("XOR"), locloc(@$));} -| ADD {$$ = new identifier_c(strdup("ADD"), locloc(@$));} -| SUB {$$ = new identifier_c(strdup("SUB"), locloc(@$));} -| MUL {$$ = new identifier_c(strdup("MUL"), locloc(@$));} -| DIV {$$ = new identifier_c(strdup("DIV"), locloc(@$));} -| MOD {$$ = new identifier_c(strdup("MOD"), locloc(@$));} -| GT {$$ = new identifier_c(strdup("GT"), locloc(@$));} -| GE {$$ = new identifier_c(strdup("GE"), locloc(@$));} -| EQ {$$ = new identifier_c(strdup("EQ"), locloc(@$));} -| LT {$$ = new identifier_c(strdup("LT"), locloc(@$));} -| LE {$$ = new identifier_c(strdup("LE"), locloc(@$));} -| NE {$$ = new identifier_c(strdup("NE"), locloc(@$));} -/* - AND_operator {$$ = il_operator_c_2_identifier_c($1);} -//NOTE: AND2 (corresponding to the source code string '&') does not clash -// with a standard function name, so should be commented out! -//| AND2_operator {$$ = il_operator_c_2_identifier_c($1);} -| OR_operator {$$ = il_operator_c_2_identifier_c($1);} -| XOR_operator {$$ = il_operator_c_2_identifier_c($1);} -| ADD_operator {$$ = il_operator_c_2_identifier_c($1);} -| SUB_operator {$$ = il_operator_c_2_identifier_c($1);} -| MUL_operator {$$ = il_operator_c_2_identifier_c($1);} -| DIV_operator {$$ = il_operator_c_2_identifier_c($1);} -| MOD_operator {$$ = il_operator_c_2_identifier_c($1);} -| GT_operator {$$ = il_operator_c_2_identifier_c($1);} -| GE_operator {$$ = il_operator_c_2_identifier_c($1);} -| EQ_operator {$$ = il_operator_c_2_identifier_c($1);} -| LT_operator {$$ = il_operator_c_2_identifier_c($1);} -| LE_operator {$$ = il_operator_c_2_identifier_c($1);} -| NE_operator {$$ = il_operator_c_2_identifier_c($1);} -*/ -; - - -derived_function_name: - identifier -| prev_declared_derived_function_name - {$$ = $1; - if (!allow_function_overloading) { - fprintf(stderr, "Function overloading not allowed. Invalid identifier %s\n", ((token_c *)($1))->value); - ERROR; - } - } -| AND - {$$ = new identifier_c("AND", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"AND\" not allowed. Invalid identifier\n"); - } -| OR - {$$ = new identifier_c("OR", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"OR\" not allowed. Invalid identifier\n"); - } -| XOR - {$$ = new identifier_c("XOR", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"XOR\" not allowed. Invalid identifier\n"); - } -| NOT - {$$ = new identifier_c("NOT", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"NOT\" not allowed. Invalid identifier\n"); - } -| MOD - {$$ = new identifier_c("MOD", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"MOD\" not allowed. Invalid identifier\n"); - } -; - - -function_declaration: -/* FUNCTION derived_function_name ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ - function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION - {$$ = new function_declaration_c($1, $3, $4, $5, locloc(@$)); - add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ - variable_name_symtable.pop(); - direct_variable_symtable.pop(); - if (allow_function_overloading) { - switch (library_element_symtable.find_value($1)) { - case prev_declared_derived_function_name_token: - /* do nothing, already in map. */ - break; - case BOGUS_TOKEN_ID: - /* Not yet in map. Must insert...*/ - library_element_symtable.insert($1, prev_declared_derived_function_name_token); - break; - default: - /* Already in map but associated with something else other than a funtion name! */ - ERROR; - } - } else { - library_element_symtable.insert($1, prev_declared_derived_function_name_token); - } - } -/* | FUNCTION derived_function_name ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ -| function_name_declaration ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION - {$$ = new function_declaration_c($1, $3, $4, $5, locloc(@$)); - add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ - variable_name_symtable.pop(); - direct_variable_symtable.pop(); - if (allow_function_overloading) { - switch (library_element_symtable.find_value($1)) { - case prev_declared_derived_function_name_token: /* do nothing, already in map. */ break; - case BOGUS_TOKEN_ID: library_element_symtable.insert($1, prev_declared_derived_function_name_token); break; - default: ERROR; - } - } else { - library_element_symtable.insert($1, prev_declared_derived_function_name_token); - } - } -/* ERROR_CHECK_BEGIN */ -| function_name_declaration elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after function name in function declaration."); yynerrs++;} -| function_name_declaration derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after function name in function declaration."); yynerrs++;} -| function_name_declaration ':' io_OR_function_var_declarations_list function_body END_FUNCTION - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no return type defined in function declaration."); yynerrs++;} -| function_name_declaration ':' error io_OR_function_var_declarations_list function_body END_FUNCTION - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid return type defined in function declaration."); yyerrok;} -| function_name_declaration ':' elementary_type_name function_body END_FUNCTION - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared in function declaration."); yynerrs++;} -| function_name_declaration ':' derived_type_name function_body END_FUNCTION - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared in function declaration."); yynerrs++;} -| function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list END_FUNCTION - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no body defined in function declaration."); yynerrs++;} -| function_name_declaration ':' derived_type_name io_OR_function_var_declarations_list END_FUNCTION - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no body defined in function declaration."); yynerrs++;} -| function_name_declaration ':' elementary_type_name END_FUNCTION - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared and body defined in function declaration."); yynerrs++;} -| function_name_declaration ':' derived_type_name END_FUNCTION - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared and body defined in function declaration."); yynerrs++;} -| function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list function_body END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locf(@3), "unclosed function declaration."); yynerrs++;} -| function_name_declaration ':' derived_type_name io_OR_function_var_declarations_list function_body END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed function declaration."); yynerrs++;} -| function_name_declaration error END_FUNCTION - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in function declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - - -/* helper symbol for function_declaration */ -/* NOTE: due to reduce/reduce conflicts between identifiers - * being reduced to either a variable or an enumerator value, - * we were forced to keep a symbol table of the names - * of all declared variables. Variables are no longer - * created from simple identifier_token, but from - * prev_declared_variable_name_token. - * - * BUT, in functions the function name itself may be used as - * a variable! In order to be able to parse this correctly, - * the token parser (flex) must return a prev_declared_variable_name_token - * when it comes across the function name, while parsing - * the function itself. - * We do this by inserting the function name into the variable - * symbol table, and having flex return a prev_declared_variable_name_token - * whenever it comes across it. - * When we finish parsing the function the variable name - * symbol table is cleared of all entries, and the function - * name is inserted into the library element symbol table. This - * means that from then onwards flex will return a - * derived_function_name_token whenever it comes across the - * function name. - * - * In order to insert the function name into the variable_name - * symbol table BEFORE the function body gets parsed, we - * need the parser to reduce a construct that contains the - * the function name. That is why we created this extra - * construct (function_name_declaration), i.e. to force - * the parser to reduce it, before parsing the function body! - */ -function_name_declaration: - FUNCTION derived_function_name - {$$ = $2; - /* the function name functions as a - * variable within the function itself! - * - * Remember that the variable_name_symtable - * is cleared once the end of the function - * is parsed. - */ - variable_name_symtable.insert($2, prev_declared_variable_name_token); - } -/* ERROR_CHECK_BEGIN */ -| FUNCTION error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no function name defined in function declaration.");} - else {print_err_msg(locf(@2), locl(@2), "invalid function name in function declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - - -/* intermediate helper symbol for function_declaration */ -io_OR_function_var_declarations_list: - io_var_declarations - {$$ = new var_declarations_list_c(locloc(@1));$$->add_element($1);} -| function_var_decls - {$$ = new var_declarations_list_c(locloc(@1));$$->add_element($1);} -| io_OR_function_var_declarations_list io_var_declarations - {$$ = $1; $$->add_element($2);} -| io_OR_function_var_declarations_list function_var_decls - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| io_OR_function_var_declarations_list retentive_var_declarations - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected retentive variable(s) declaration in function declaration."); yynerrs++;} -| io_OR_function_var_declarations_list located_var_declarations - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected located variable(s) declaration in function declaration."); yynerrs++;} -| io_OR_function_var_declarations_list external_var_declarations - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected external variable(s) declaration in function declaration."); yynerrs++;} -| io_OR_function_var_declarations_list global_var_declarations - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected global variable(s) declaration in function declaration."); yynerrs++;} -| io_OR_function_var_declarations_list incompl_located_var_declarations - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected incomplete located variable(s) declaration in function declaration."); yynerrs++;} -| io_OR_function_var_declarations_list temp_var_decls - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected temporary located variable(s) declaration in function declaration."); yynerrs++;} -| io_OR_function_var_declarations_list non_retentive_var_decls - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected non-retentive variable(s) declaration in function declaration."); yynerrs++;} -/*| io_OR_function_var_declarations_list access_declarations - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected access variable(s) declaration in function declaration."); yynerrs++;}*/ -| io_OR_function_var_declarations_list instance_specific_initializations - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected instance specific initialization(s) in function declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -io_var_declarations: - input_declarations -| output_declarations -| input_output_declarations -; - - -function_var_decls: - VAR CONSTANT var2_init_decl_list END_VAR - {$$ = new function_var_decls_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} -| VAR var2_init_decl_list END_VAR - {$$ = new function_var_decls_c(NULL, $2, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| VAR error var2_init_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR' in function variable(s) declaration."); yyerrok;} -| VAR CONSTANT error var2_init_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant function variable(s) declaration."); yyerrok;} -| VAR var2_init_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed function variable(s) declaration."); yyerrok;} -| VAR CONSTANT var2_init_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant function variable(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - -/* intermediate helper symbol for function_var_decls */ -var2_init_decl_list: - var2_init_decl ';' - {$$ = new var2_init_decl_list_c(locloc(@$)); $$->add_element($1);} -| var2_init_decl_list var2_init_decl ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| var2_init_decl error - {$$ = new var2_init_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of function variable(s) declaration."); yyerrok;} -| var2_init_decl_list var2_init_decl error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of function variable(s) declaration."); yyerrok;} -| var2_init_decl_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid function variable(s) declaration."); yyerrok;} -| var2_init_decl_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after function variable(s) declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -function_body: - statement_list {$$ = $1;} /* if we leave it for the default action we get a type clash! */ -| instruction_list {$$ = $1;} /* if we leave it for the default action we get a type clash! */ -/* -| ladder_diagram -| function_block_diagram -*/ -; - - -var2_init_decl: - var1_init_decl -| array_var_init_decl -| structured_var_init_decl -| string_var_declaration -; - - - -/*****************************/ -/* B 1.5.2 - Function Blocks */ -/*****************************/ -function_block_type_name: - prev_declared_derived_function_block_name -| standard_function_block_name -; - - -standard_function_block_name: standard_function_block_name_token {$$ = new identifier_c($1, locloc(@$));}; - -derived_function_block_name: identifier; - - -function_block_declaration: - FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK - {$$ = new function_block_declaration_c($2, $3, $4, locloc(@$)); - add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ - library_element_symtable.insert($2, prev_declared_derived_function_block_name_token); - /* Clear the variable_name_symtable. Since - * we have finished parsing the function block, - * the variable names are now out of scope, so - * are no longer valid! - */ - variable_name_symtable.pop(); - direct_variable_symtable.pop(); - } -/* ERROR_CHECK_BEGIN */ -| FUNCTION_BLOCK io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in function block declaration."); yynerrs++;} -| FUNCTION_BLOCK error io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name in function block declaration."); yyerrok;} -| FUNCTION_BLOCK derived_function_block_name function_block_body END_FUNCTION_BLOCK - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared in function declaration."); yynerrs++;} -| FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list END_FUNCTION_BLOCK - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no body defined in function block declaration."); yynerrs++;} -| FUNCTION_BLOCK derived_function_block_name END_FUNCTION_BLOCK - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared and body defined in function block declaration."); yynerrs++;} -| FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "no variable(s) declared and body defined in function block declaration."); yynerrs++;} -| FUNCTION_BLOCK error END_FUNCTION_BLOCK - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in function block declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - - -/* intermediate helper symbol for function_declaration */ -/* { io_var_declarations | other_var_declarations } */ -/* - * NOTE: we re-use the var_declarations_list_c - */ -io_OR_other_var_declarations_list: - io_var_declarations - {$$ = new var_declarations_list_c(locloc(@$));$$->add_element($1);} -| other_var_declarations - {$$ = new var_declarations_list_c(locloc(@$));$$->add_element($1);} -| io_OR_other_var_declarations_list io_var_declarations - {$$ = $1; $$->add_element($2);} -| io_OR_other_var_declarations_list other_var_declarations - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| io_OR_other_var_declarations_list located_var_declarations - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected located variable(s) declaration in function block declaration."); yynerrs++;} -| io_OR_other_var_declarations_list global_var_declarations - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected global variable(s) declaration in function block declaration."); yynerrs++;} -/*| io_OR_other_var_declarations_list access_declarations - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected access variable(s) declaration in function block declaration."); yynerrs++;}*/ -| io_OR_other_var_declarations_list instance_specific_initializations - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected instance specific initialization(s) in function block declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - -/* NOTE: - * The IEC specification gives the following definition: - * other_var_declarations ::= - * external_var_declarations - * | var_declarations - * | retentive_var_declarations - * | non_retentive_var_declarations - * | temp_var_decls - * | incompl_located_var_declarations - * - * Nvertheless, the symbol non_retentive_var_declarations - * is not defined in the spec. This seems to me (Mario) - * to be a typo, so non_retentive_var_declarations - * has been replaced with non_retentive_var_decls - * in the following rule! - */ -other_var_declarations: - temp_var_decls -| non_retentive_var_decls -| external_var_declarations -| var_declarations -| retentive_var_declarations -| incompl_located_var_declarations -; - - -temp_var_decls: - VAR_TEMP temp_var_decls_list END_VAR - {$$ = new temp_var_decls_c($2, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| VAR_TEMP END_VAR - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in temporary variable(s) declaration."); yynerrs++;} -| VAR_TEMP temp_var_decls_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "unclosed temporary variable(s) declaration."); yyerrok;} -| VAR_TEMP error temp_var_decls_list END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_TEMP' in function variable(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -/* intermediate helper symbol for temp_var_decls */ -temp_var_decls_list: - temp_var_decl ';' - {$$ = new temp_var_decls_list_c(locloc(@$)); $$->add_element($1);} -| temp_var_decls_list temp_var_decl ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| error ';' - {$$ = new temp_var_decls_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid temporary variable(s) declaration."); yyerrok;} -| temp_var_decl error - {$$ = new temp_var_decls_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of temporary variable(s) declaration."); yyerrok;} -| temp_var_decls_list temp_var_decl error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of temporary variable(s) declaration."); yyerrok;} -| temp_var_decls_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid temporary variable(s) declaration."); yyerrok;} -| temp_var_decls_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after temporary variable(s) declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -non_retentive_var_decls: - VAR NON_RETAIN var_init_decl_list END_VAR - {$$ = new non_retentive_var_decls_c($3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| VAR NON_RETAIN var_init_decl_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unclosed non-retentive temporary variable(s) declaration."); yyerrok;} -| VAR NON_RETAIN error var_init_decl_list END_VAR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive temporary variable(s) declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - - -function_block_body: - statement_list {$$ = $1;} -| instruction_list {$$ = $1;} -| sequential_function_chart {$$ = $1;} -/* -| ladder_diagram -| function_block_diagram -| -*/ -; - - - - -/**********************/ -/* B 1.5.3 - Programs */ -/**********************/ -program_type_name: identifier; - - -program_declaration: - PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM - {$$ = new program_declaration_c($2, $3, $4, locloc(@$)); - library_element_symtable.insert($2, prev_declared_program_type_name_token); - /* Clear the variable_name_symtable. Since - * we have finished parsing the program declaration, - * the variable names are now out of scope, so - * are no longer valid! - */ - variable_name_symtable.pop(); - direct_variable_symtable.pop(); - } -/* ERROR_CHECK_BEGIN */ -| PROGRAM program_var_declarations_list function_block_body END_PROGRAM - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no program name defined in program declaration.");} -| PROGRAM error program_var_declarations_list function_block_body END_PROGRAM - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid program name in program declaration."); yyerrok;} -| PROGRAM program_type_name function_block_body END_PROGRAM - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared in program declaration."); yynerrs++;} -| PROGRAM program_type_name program_var_declarations_list END_PROGRAM - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no body defined in program declaration."); yynerrs++;} -| PROGRAM program_type_name END_PROGRAM - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared and body defined in program declaration."); yynerrs++;} -| PROGRAM program_type_name program_var_declarations_list function_block_body END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed program declaration."); yynerrs++;} -| PROGRAM error END_PROGRAM - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in program declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -/* helper symbol for program_declaration */ -/* - * NOTE: we re-use the var_declarations_list_c - */ -program_var_declarations_list: - io_var_declarations - {$$ = new var_declarations_list_c(locloc(@$)); $$->add_element($1);} -| other_var_declarations - {$$ = new var_declarations_list_c(locloc(@$)); $$->add_element($1);} -| located_var_declarations - {$$ = new var_declarations_list_c(locloc(@$)); $$->add_element($1);} -| program_var_declarations_list io_var_declarations - {$$ = $1; $$->add_element($2);} -| program_var_declarations_list other_var_declarations - {$$ = $1; $$->add_element($2);} -| program_var_declarations_list located_var_declarations - {$$ = $1; $$->add_element($2);} -/* -| program_var_declarations_list program_access_decls - {$$ = $1; $$->add_element($2);} -*/ -/* ERROR_CHECK_BEGIN */ -| program_var_declarations_list global_var_declarations - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected global variable(s) declaration in function block declaration."); yynerrs++;} -/*| program_var_declarations_list access_declarations - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected access variable(s) declaration in function block declaration."); yynerrs++;}*/ -| program_var_declarations_list instance_specific_initializations - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected instance specific initialization(s) in function block declaration."); yynerrs++; - } -/* ERROR_CHECK_END */ -; - - -/* TODO ... */ -/* -program_access_decls: - VAR_ACCESS program_access_decl_list END_VAR -; -*/ - -/* helper symbol for program_access_decls */ -/* -program_access_decl_list: - program_access_decl ';' -| program_access_decl_list program_access_decl ';' -; -*/ - -/* -program_access_decl: - access_name ':' symbolic_variable ':' non_generic_type_name -| access_name ':' symbolic_variable ':' non_generic_type_name direction -; -*/ - - - -/********************************************/ -/* B 1.6 Sequential Function Chart elements * -/********************************************/ - -sequential_function_chart: - sfc_network - {$$ = new sequential_function_chart_c(locloc(@$)); $$->add_element($1);} -| sequential_function_chart sfc_network - {$$ = $1; $$->add_element($2);} -; - -sfc_network: - initial_step - {$$ = new sfc_network_c(locloc(@$)); $$->add_element($1);} -| sfc_network step - {$$ = $1; $$->add_element($2);} -| sfc_network transition - {$$ = $1; $$->add_element($2);} -| sfc_network action - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| sfc_network error - {$$ = $1; print_err_msg(locl(@1), locf(@2), "unexpected token after SFC network in sequencial function chart."); yyerrok;} -/* ERROR_CHECK_END */ -; - -initial_step: - INITIAL_STEP step_name ':' action_association_list END_STEP -// INITIAL_STEP identifier ':' action_association_list END_STEP - {$$ = new initial_step_c($2, $4, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| INITIAL_STEP ':' action_association_list END_STEP - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "no step name defined in initial step declaration."); yynerrs++;} -| INITIAL_STEP error ':' action_association_list END_STEP - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid step name defined in initial step declaration."); yyerrok;} -| INITIAL_STEP step_name action_association_list END_STEP - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':' missing after step name in initial step declaration."); yynerrs++;} -| INITIAL_STEP step_name ':' error END_STEP - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid action association list in initial step declaration."); yyerrok;} -| INITIAL_STEP step_name ':' action_association_list END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed initial step declaration."); yynerrs++;} -| INITIAL_STEP error END_STEP - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in initial step declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - -step: - STEP step_name ':' action_association_list END_STEP -// STEP identifier ':' action_association_list END_STEP - {$$ = new step_c($2, $4, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| STEP ':' action_association_list END_STEP - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no step name defined in step declaration."); yynerrs++;} -| STEP error ':' action_association_list END_STEP - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid step name defined in step declaration."); yyerrok;} -| STEP step_name action_association_list END_STEP - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':' missing after step name in step declaration."); yynerrs++;} -| STEP step_name ':' error END_STEP - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid action association list in step declaration."); yyerrok;} -| STEP step_name ':' action_association_list END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@3), "invalid action association list in step declaration."); yynerrs++;} -| STEP error END_STEP - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in step declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - -/* helper symbol for: - * - initial_step - * - step - */ -action_association_list: - /* empty */ - {$$ = new action_association_list_c(locloc(@$));} -| action_association_list action_association ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| action_association_list action_association error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of action association declaration."); yyerrok;} -| action_association_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after action association declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -// step_name: identifier; -step_name: any_identifier; - -action_association: - action_name '(' {cmd_goto_sfc_qualifier_state();} action_qualifier {cmd_pop_state();} indicator_name_list ')' - {$$ = new action_association_c($1, $4, $6, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -/*| action_name '(' error ')' - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid qualifier defined in action association."); yyerrok;}*/ -/* ERROR_CHECK_END */ -; - -/* helper symbol for action_association */ -indicator_name_list: - /* empty */ - {$$ = new indicator_name_list_c(locloc(@$));} -| indicator_name_list ',' indicator_name - {$$ = $1; $$->add_element($3);} -/* ERROR_CHECK_BEGIN */ -| indicator_name_list indicator_name - {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing at end of action association declaration."); yynerrs++;} -| indicator_name_list ',' error - {$$ = $1; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no indicator defined in indicator list.");} - else {print_err_msg(locf(@3), locl(@3), "invalid indicator in indicator list."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -// action_name: identifier; -action_name: any_identifier; - -action_qualifier: - /* empty */ - {$$ = NULL;} -| qualifier - {$$ = new action_qualifier_c($1, NULL, locloc(@$));} -| timed_qualifier ',' action_time - {$$ = new action_qualifier_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| timed_qualifier action_time - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "',' missing between timed qualifier and action time in action qualifier."); yynerrs++;} -| timed_qualifier ',' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no action time defined in action qualifier.");} - else {print_err_msg(locf(@3), locl(@3), "invalid action time in action qualifier."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -qualifier: - N {$$ = new qualifier_c(strdup("N"), locloc(@$));} -| R {$$ = new qualifier_c(strdup("R"), locloc(@$));} -| S {$$ = new qualifier_c(strdup("S"), locloc(@$));} -| P {$$ = new qualifier_c(strdup("P"), locloc(@$));} -; - -timed_qualifier: - L {$$ = new timed_qualifier_c(strdup("L"), locloc(@$));} -| D {$$ = new timed_qualifier_c(strdup("D"), locloc(@$));} -| SD {$$ = new timed_qualifier_c(strdup("SD"), locloc(@$));} -| DS {$$ = new timed_qualifier_c(strdup("DS"), locloc(@$));} -| SL {$$ = new timed_qualifier_c(strdup("SL"), locloc(@$));} -; - -action_time: - duration -| variable -; - -indicator_name: variable; - -// transition_name: identifier; -transition_name: any_identifier; - - -steps: - step_name - {$$ = new steps_c($1, NULL, locloc(@$));} -| '(' step_name_list ')' - {$$ = new steps_c(NULL, $2, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| '(' step_name_list error - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "expecting ')' at the end of step list in transition declaration."); yyerrok;} -| '(' error ')' - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid step list in transition declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - -step_name_list: - step_name ',' step_name - {$$ = new step_name_list_c(locloc(@$)); $$->add_element($1); $$->add_element($3);} -| step_name_list ',' step_name - {$$ = $1; $$->add_element($3);} -/* ERROR_CHECK_BEGIN */ -| step_name_list step_name - {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in step list."); yynerrs++;} -| step_name_list ',' error - {$$ = $1; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no step name defined in step list.");} - else {print_err_msg(locf(@3), locl(@3), "invalid step name in step list."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -/* NOTE: flex will automatically pop() out of body_state to previous state. - * We do not need to give a command from bison to return to previous flex state, - * after forcing flex to go to body_state. - */ -transition: - TRANSITION transition_priority - FROM steps TO steps - {cmd_goto_body_state();} transition_condition - END_TRANSITION - {$$ = new transition_c(NULL, $2, $4, $6, $8, locloc(@$));} -//| TRANSITION identifier FROM steps TO steps ... -| TRANSITION transition_name transition_priority - FROM steps TO steps - {cmd_goto_body_state();} transition_condition - END_TRANSITION - {$$ = new transition_c($2, $3, $5, $7, $9, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| TRANSITION error transition_priority FROM steps TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid transition name defined in transition declaration."); yyerrok;} -| TRANSITION transition_name error FROM steps TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid transition priority defined in transition declaration."); yyerrok;} -| TRANSITION transition_priority FROM TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no origin step(s) defined in transition declaration."); yynerrs++;} -| TRANSITION transition_name transition_priority FROM TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no origin step(s) defined in transition declaration."); yynerrs++;} -| TRANSITION transition_priority FROM error TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid origin step(s) defined in transition declaration."); yyerrok;} -| TRANSITION transition_name transition_priority FROM error TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION - {$$ = NULL; print_err_msg(locf(@5), locl(@5), "invalid origin step(s) defined in transition declaration."); yyerrok;} -| TRANSITION transition_priority FROM steps steps {cmd_goto_body_state();} transition_condition END_TRANSITION - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "'TO' missing between origin step(s) and destination step(s) in transition declaration."); yynerrs++;} -| TRANSITION transition_name transition_priority FROM steps steps {cmd_goto_body_state();} transition_condition END_TRANSITION - {$$ = NULL; print_err_msg(locl(@5), locf(@6), "'TO' missing between origin step(s) and destination step(s) in transition declaration."); yynerrs++;} -| TRANSITION transition_priority FROM steps TO {cmd_goto_body_state();} transition_condition END_TRANSITION - {$$ = NULL; print_err_msg(locl(@5), locf(@7), "no destination step(s) defined in transition declaration."); yynerrs++;} -| TRANSITION transition_name transition_priority FROM steps TO {cmd_goto_body_state();} transition_condition END_TRANSITION - {$$ = NULL; print_err_msg(locl(@6), locf(@8), "no destination step(s) defined in transition declaration."); yynerrs++;} -| TRANSITION transition_priority FROM steps TO error {cmd_goto_body_state();} transition_condition END_TRANSITION - {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid destination step(s) defined in transition declaration."); yyerrok;} -| TRANSITION transition_name transition_priority FROM steps TO error {cmd_goto_body_state();} transition_condition END_TRANSITION - {$$ = NULL; print_err_msg(locf(@7), locl(@7), "invalid destination step(s) defined in transition declaration."); yyerrok;} -| TRANSITION transition_priority {cmd_goto_body_state();} transition_condition END_TRANSITION - {$$ = NULL; print_err_msg(locl(@2), locf(@4), "no origin and destination step(s) defined in transition declaration."); yynerrs++;} -| TRANSITION transition_name transition_priority {cmd_goto_body_state();} transition_condition END_TRANSITION - {$$ = NULL; print_err_msg(locl(@3), locf(@5), "no origin and destination step(s) defined in transition declaration."); yynerrs++;} -/*| TRANSITION transition_priority FROM steps TO steps {cmd_goto_body_state();} transition_condition error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@6), "unclosed transition declaration."); yyerrok;} -| TRANSITION transition_name transition_priority FROM steps TO steps {cmd_goto_body_state();} transition_condition error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@7), "unclosed transition declaration."); yyerrok;}*/ -| TRANSITION error END_TRANSITION - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in transition declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - -transition_priority: - /* empty */ - {$$ = NULL;} -| '(' {cmd_goto_sfc_priority_state();} PRIORITY {cmd_pop_state();} ASSIGN integer ')' - {$$ = $6;} -/* ERROR_CHECK_BEGIN -| '(' ASSIGN integer ')' - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'PRIORITY' missing between '(' and ':=' in transition declaration with priority."); yynerrs++;} -| '(' error ASSIGN integer ')' - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "expecting 'PRIORITY' between '(' and ':=' in transition declaration with priority."); yyerrok;} - ERROR_CHECK_END */ -; - - -transition_condition: - ':' eol_list simple_instr_list - {$$ = new transition_condition_c($3, NULL, locloc(@$));} -| ASSIGN expression ';' - {$$ = new transition_condition_c(NULL, $2, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| eol_list simple_instr_list - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing before IL condition in transition declaration."); yynerrs++;} -| ':' eol_list error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no instructions defined in IL condition of transition declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid instructions in IL condition of transition declaration."); yyclearin;} - yyerrok; - } -| ASSIGN ';' - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no expression defined in ST condition of transition declaration."); yynerrs++;} -| ASSIGN error ';' - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid expression defined in ST condition of transition declaration."); yyerrok;} -| ASSIGN expression error - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "expecting ';' after expression defined in ST condition of transition declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - - -action: -// ACTION identifier ':' ... - ACTION action_name {cmd_goto_body_state();} action_body END_ACTION - {$$ = new action_c($2, $4, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| ACTION {cmd_goto_body_state();} action_body END_ACTION - {$$ = NULL; print_err_msg(locl(@1), locf(@3), "no action name defined in action declaration."); yynerrs++;} -| ACTION error {cmd_goto_body_state();} action_body END_ACTION - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid action name defined in action declaration."); yyerrok;} -| ACTION action_name {cmd_goto_body_state();} function_block_body END_ACTION - {$$ = NULL; print_err_msg(locl(@2), locf(@4), "':' missing after action name in action declaration."); yynerrs++;} -/*| ACTION action_name {cmd_goto_body_state();} action_body END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed action declaration."); yyerrok;}*/ -| ACTION error END_ACTION - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in action declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - -action_body: - ':' function_block_body - {$$ = $2;} -/* ERROR_CHECK_BEGIN */ -| ':' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no body defined in action declaration.");} - else {print_err_msg(locf(@2), locl(@2), "invalid body defined in action declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -/********************************/ -/* B 1.7 Configuration elements */ -/********************************/ -/* NOTE: - * It is not clear from reading the specification to which namespace - * the names of resources, tasks and programs belong to. - * - * The following syntax assumes that resource and program names belong to the - * same namespace as the variables defined within - * the resource/configuration (i.e. VAR_GLOBAL). - * Task names belong to a namespace all of their own, since they don't - * produce conflicts in the syntax parser, so we might just as well - * leave them be! ;-) - * The above decision was made taking into - * account that inside a VAR_CONFIG declaration global variables - * may be referenced starting off from the resource name as: - * resource_name.program_name.variable_name - * Notice how resource names and program names are used in a very similar - * manner as are variable names. - * Using a single namespace for all the above mentioned names - * also makes it easier to write the syntax parser!! ;-) Using a private - * namespace for each of the name types (resource names, program names, - * global varaiable names), i.e. letting the names be re-used across - * each of the groups (resource, program, global variables), produces - * reduce/reduce conflicts in the syntax parser. Actually, it is only - * the resource names that need to be distinguished into a - * prev_declared_resource_name so as not to conflict with [gloabl] variable - * names in the 'data' construct. - * The program names are only tracked to make sure that two programs do not - * get the same name. - * - * Using a single namespace does have the drawback that the user will - * not be able to re-use names for resources or programs if these - * have already been used to name a variable! - * - * If it ever becomes necessary to change this interpretation of - * the syntax, then this section of the syntax parser must be updated! - */ -prev_declared_global_var_name: prev_declared_global_var_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_resource_name: prev_declared_resource_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_program_name: prev_declared_program_name_token {$$ = new identifier_c($1, locloc(@$));}; -// prev_declared_task_name: prev_declared_task_name_token {$$ = new identifier_c($1, locloc(@$));}; - - - - - - -configuration_name: identifier; - -/* NOTE: The specification states that valid resource type names - * are implementation defined, i.e. each implementaion will define - * what resource types it supports. - * We are implementing this syntax parser to be used by any - * implementation, so at the moment we accept any identifier - * as a resource type name. - * This implementation should probably be changed in the future. We - * should probably have a resource_type_name_token, and let the - * implementation load the global symbol library with the - * accepted resource type names before parsing the code. - * - */ -resource_type_name: any_identifier; - -configuration_declaration: - CONFIGURATION configuration_name - optional_global_var_declarations - single_resource_declaration - {variable_name_symtable.pop(); - direct_variable_symtable.pop();} - optional_access_declarations - optional_instance_specific_initializations - END_CONFIGURATION - {$$ = new configuration_declaration_c($2, $3, $4, $6, $7, locloc(@$)); - library_element_symtable.insert($2, prev_declared_configuration_name_token); - variable_name_symtable.pop(); - direct_variable_symtable.pop(); - } -| CONFIGURATION configuration_name - optional_global_var_declarations - resource_declaration_list - optional_access_declarations - optional_instance_specific_initializations - END_CONFIGURATION - {$$ = new configuration_declaration_c($2, $3, $4, $5, $6, locloc(@$)); - library_element_symtable.insert($2, prev_declared_configuration_name_token); - variable_name_symtable.pop(); - direct_variable_symtable.pop(); -} -/* ERROR_CHECK_BEGIN */ -| CONFIGURATION - optional_global_var_declarations - single_resource_declaration - {variable_name_symtable.pop(); - direct_variable_symtable.pop();} - optional_access_declarations - optional_instance_specific_initializations - END_CONFIGURATION - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no configuration name defined in configuration declaration."); yynerrs++;} -| CONFIGURATION - optional_global_var_declarations - resource_declaration_list - optional_access_declarations - optional_instance_specific_initializations - END_CONFIGURATION - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no configuration name defined in configuration declaration."); yynerrs++;} -| CONFIGURATION error - optional_global_var_declarations - single_resource_declaration - {variable_name_symtable.pop(); - direct_variable_symtable.pop();} - optional_access_declarations - optional_instance_specific_initializations - END_CONFIGURATION - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid configuration name defined in configuration declaration."); yyerrok;} -| CONFIGURATION error - optional_global_var_declarations - resource_declaration_list - optional_access_declarations - optional_instance_specific_initializations - END_CONFIGURATION - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid configuration name defined in configuration declaration."); yyerrok;} -| CONFIGURATION configuration_name - optional_global_var_declarations - optional_access_declarations - optional_instance_specific_initializations - END_CONFIGURATION - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no resource(s) defined in configuration declaration."); yynerrs++;} -| CONFIGURATION configuration_name - optional_global_var_declarations - error - optional_access_declarations - optional_instance_specific_initializations - END_CONFIGURATION - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid resource(s) defined in configuration declaration."); yyerrok;} -/*| CONFIGURATION configuration_name - optional_global_var_declarations - single_resource_declaration - {variable_name_symtable.pop(); - direct_variable_symtable.pop();} - optional_access_declarations - optional_instance_specific_initializations - END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed configuration declaration."); yyerrok;}*/ -| CONFIGURATION configuration_name - optional_global_var_declarations - resource_declaration_list - optional_access_declarations - optional_instance_specific_initializations - END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed configuration declaration."); yyerrok;} -| CONFIGURATION error END_CONFIGURATION - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in configuration declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - -// helper symbol for -// - configuration_declaration -// - resource_declaration -// -optional_global_var_declarations: - // empty - {$$ = NULL;} -| global_var_declarations -; - - -// helper symbol for configuration_declaration // -optional_access_declarations: - // empty - {$$ = NULL;} -//| access_declarations -; - -// helper symbol for configuration_declaration // -optional_instance_specific_initializations: - // empty - {$$ = NULL;} -| instance_specific_initializations -; - -// helper symbol for configuration_declaration // -resource_declaration_list: - resource_declaration - {$$ = new resource_declaration_list_c(locloc(@$)); $$->add_element($1);} -| resource_declaration_list resource_declaration - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| resource_declaration_list error - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected token after resource declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -resource_declaration: - RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} resource_name ON resource_type_name - optional_global_var_declarations - single_resource_declaration - END_RESOURCE - {$$ = new resource_declaration_c($3, $5, $6, $7, locloc(@$)); - variable_name_symtable.pop(); - direct_variable_symtable.pop(); - variable_name_symtable.insert($3, prev_declared_resource_name_token); - } -/* ERROR_CHECK_BEGIN */ -| RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} ON resource_type_name - optional_global_var_declarations - single_resource_declaration - END_RESOURCE - {$$ = NULL; print_err_msg(locl(@1), locf(@3), "no resource name defined in resource declaration."); yynerrs++;} -/*| RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} resource_name ON resource_type_name - optional_global_var_declarations - single_resource_declaration - END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@5), "unclosed resource declaration."); yyerrok;}*/ -| RESOURCE error END_RESOURCE - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in resource declaration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -single_resource_declaration: - task_configuration_list program_configuration_list - {$$ = new single_resource_declaration_c($1, $2, locloc(@$));} -; - - -// helper symbol for single_resource_declaration // -task_configuration_list: - // empty - {$$ = new task_configuration_list_c(locloc(@$));} -| task_configuration_list task_configuration ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| task_configuration_list task_configuration error - {$$ = $1; print_err_msg(locl(@1), locf(@2), "';' missing at the end of task configuration in resource declaration."); yyerrok;} -| task_configuration_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after task configuration in resource declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -// helper symbol for single_resource_declaration // -program_configuration_list: - program_configuration ';' - {$$ = new program_configuration_list_c(locloc(@$)); $$->add_element($1);} -| program_configuration_list program_configuration ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| program_configuration error - {$$ = new program_configuration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at the end of program configuration in resource declaration."); yyerrok;} -| program_configuration_list program_configuration error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of program configuration in resource declaration."); yyerrok;} -| program_configuration_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid program configuration in resource declaration."); yyerrok;} -| program_configuration_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after program configuration in resource declaration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -resource_name: identifier; - -/* -access_declarations: - VAR_ACCESS access_declaration_list END_VAR - {$$ = NULL;} -// ERROR_CHECK_BEGIN // -| VAR_ACCESS END_VAR - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in access variable(s) declaration."); yynerrs++;} -| VAR_ACCESS error access_declaration_list END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_ACCESS' in access variable(s) declaration."); yyerrok;} -| VAR_ACCESS access_declaration_list error END_VAR - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed access variable(s) declaration."); yyerrok;} -| VAR_ACCESS error END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in access variable(s) declaration."); yyerrok;} -// ERROR_CHECK_END // -; - -// helper symbol for access_declarations // -access_declaration_list: - access_declaration ';' -| access_declaration_list access_declaration ';' -// ERROR_CHECK_BEGIN // -| error ';' - {$$ = // create a new list //; - print_err_msg(locf(@1), locl(@1), "invalid access variable declaration."); yyerrok;} -| access_declaration error - {$$ = // create a new list //; - print_err_msg(locl(@1), locf(@2), "';' missing at the end of access variable declaration."); yyerrok;} -| access_declaration_list access_declaration error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of access variable declaration."); yyerrok;} -| access_declaration_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid access variable declaration."); yyerrok;} -| access_declaration_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after access variable declaration."); yynerrs++;} -// ERROR_CHECK_END // -; - - -access_declaration: - access_name ':' access_path ':' non_generic_type_name -| access_name ':' access_path ':' non_generic_type_name direction -; - - -access_path: - prev_declared_direct_variable -| prev_declared_resource_name '.' prev_declared_direct_variable -| any_fb_name_list symbolic_variable -| prev_declared_resource_name '.' any_fb_name_list symbolic_variable -| prev_declared_program_name '.' any_fb_name_list symbolic_variable -| prev_declared_resource_name '.' prev_declared_program_name '.' any_fb_name_list symbolic_variable -; -*/ - -// helper symbol for -// - access_path -// - instance_specific_init -// -/* NOTE: The fb_name_list refers to funtion block variables - * that have been declared in a scope outside the one we are - * currently parsing, so we must accept them to be any_identifier! - * - * Beware that other locations of this syntax parser also require - * a fb_name_list. In those locations the function blocks are being declared, - * so only currently un-used identifiers (i.e. identifier) may be accepted. - * - * In order to distinguish the two, here we use any_fb_name_list, while - * in the the locations we simply use fb_name_list! - */ -any_fb_name_list: - // empty - {$$ = new any_fb_name_list_c(locloc(@$));} -//| fb_name_list fb_name '.' -| any_fb_name_list any_identifier '.' - {$$ = $1; $$->add_element($2);} -; - - - -global_var_reference: -// [resource_name '.'] global_var_name ['.' structure_element_name] // - prev_declared_global_var_name - {$$ = new global_var_reference_c(NULL, $1, NULL, locloc(@$));} -| prev_declared_global_var_name '.' structure_element_name - {$$ = new global_var_reference_c(NULL, $1, $3, locloc(@$));} -| prev_declared_resource_name '.' prev_declared_global_var_name - {$$ = new global_var_reference_c($1, $3, NULL, locloc(@$));} -| prev_declared_resource_name '.' prev_declared_global_var_name '.' structure_element_name - {$$ = new global_var_reference_c($1, $3, $5, locloc(@$));} -; - - -//access_name: identifier; - - -program_output_reference: -/* NOTE: - * program_output_reference is merely used within data_source. - * data_source is merely used within task_initialization - * task_initialization appears in a configuration declaration - * _before_ the programs are declared, so we cannot use - * prev_declared_program_name, as what might seem correct at first. - * - * The semantic checker must later check whether the identifier - * used really refers to a program declared after the task - * initialization! - */ -// prev_declared_program_name '.' symbolic_variable - program_name '.' symbolic_variable - {$$ = new program_output_reference_c($1, $3, locloc(@$));} -; - -program_name: identifier; - -/* -direction: - READ_WRITE - {$$ = NULL;} -| READ_ONLY - {$$ = NULL;} -; -*/ - -task_configuration: - TASK task_name task_initialization - {$$ = new task_configuration_c($2, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| TASK task_initialization - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no task name defined in task declaration."); yynerrs++;} -| TASK error task_initialization - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid task name defined in task declaration."); yyerrok;} -| TASK task_name error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no task initialization defined in task declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid task initialization in task declaration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -/* NOTE: The specification does not mention the namespace to which task names - * should belong to. Unlike resource and program names, for the moment we - * let the task names belong to their own private namespace, as they do not - * produce any conflicts in the syntax parser. - * If in the future our interpretation of the spec. turns out to be incorrect, - * the definition of task_name may have to be changed! - */ -task_name: any_identifier; - - -task_initialization: -// '(' [SINGLE ASSIGN data_source ','] [INTERVAL ASSIGN data_source ','] PRIORITY ASSIGN integer ')' // - '(' {cmd_goto_task_init_state();} task_initialization_single task_initialization_interval task_initialization_priority ')' - {$$ = new task_initialization_c($3, $4, $5, locloc(@$));} -; - - -task_initialization_single: -// [SINGLE ASSIGN data_source ','] - /* empty */ - {$$ = NULL;} -| SINGLE ASSIGN {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} - {$$ = $4;} -/* ERROR_CHECK_BEGIN */ -| SINGLE {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} - {$$ = NULL; print_err_msg(locl(@1), locf(@3), "':=' missing after 'SINGLE' in task initialization."); yynerrs++;} -| SINGLE ASSIGN {cmd_pop_state();} ',' {cmd_goto_task_init_state();} - {$$ = NULL; print_err_msg(locl(@2), locf(@4), "no data source defined in 'SINGLE' statement of task initialization."); yynerrs++;} -| SINGLE ASSIGN {cmd_pop_state();} error ',' {cmd_goto_task_init_state();} - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid data source defined in 'SINGLE' statement of task initialization."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -task_initialization_interval: -// [INTERVAL ASSIGN data_source ','] - /* empty */ - {$$ = NULL;} -| INTERVAL ASSIGN {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} - {$$ = $4;} -/* ERROR_CHECK_BEGIN */ -| INTERVAL {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} - {$$ = NULL; print_err_msg(locl(@1), locf(@3), "':=' missing after 'INTERVAL' in task initialization.");} -| INTERVAL ASSIGN {cmd_pop_state();} ',' {cmd_goto_task_init_state();} - {$$ = NULL; print_err_msg(locl(@2), locf(@4), "no data source defined in 'INTERVAL' statement of task initialization."); yynerrs++;} -| INTERVAL ASSIGN {cmd_pop_state();} error ',' {cmd_goto_task_init_state();} - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid data source defined in 'INTERVAL' statement of task initialization."); yyerrok;} -/* ERROR_CHECK_END */ -; - - - -task_initialization_priority: -// PRIORITY ASSIGN integer - PRIORITY ASSIGN {cmd_pop_state();} integer - {$$ = $4;} -/* ERROR_CHECK_BEGIN */ -| PRIORITY {cmd_pop_state();} integer - {$$ = NULL; print_err_msg(locl(@1), locf(@3), "':=' missing after 'PRIORITY' in task initialization."); yynerrs++;} -| PRIORITY ASSIGN {cmd_pop_state();} error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@4), "no priority number defined in 'PRIORITY' statement of task initialization.");} - else {print_err_msg(locf(@4), locl(@4), "invalid priority number in 'PRIORITY' statement of task initialization."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - - -data_source: - constant -| global_var_reference -| program_output_reference -| prev_declared_direct_variable -; - -program_configuration: -// PROGRAM [RETAIN | NON_RETAIN] program_name [WITH task_name] ':' program_type_name ['(' prog_conf_elements ')'] // - PROGRAM program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements - {$$ = new program_configuration_c(NULL, $2, $3, $5, $6, locloc(@$)); - variable_name_symtable.insert($2, prev_declared_program_name_token); - } -| PROGRAM RETAIN program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements - {$$ = new program_configuration_c(new retain_option_c(locloc(@2)), $3, $4, $6, $7, locloc(@$)); - variable_name_symtable.insert($3, prev_declared_program_name_token); - } -| PROGRAM NON_RETAIN program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements - {$$ = new program_configuration_c(new non_retain_option_c(locloc(@2)), $3, $4, $6, $7, locloc(@$)); - variable_name_symtable.insert($3, prev_declared_program_name_token); - } -/* ERROR_CHECK_BEGIN */ -| PROGRAM program_name optional_task_name ':' identifier optional_prog_conf_elements - {$$ = NULL; print_err_msg(locf(@5), locl(@5), "invalid program type name after ':' in program configuration."); yynerrs++;} -| PROGRAM RETAIN program_name optional_task_name ':' identifier optional_prog_conf_elements - {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid program type name after ':' in program configuration."); yynerrs++;} -| PROGRAM NON_RETAIN program_name optional_task_name ':' identifier optional_prog_conf_elements - {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid program type name after ':' in program configuration."); yynerrs++;} -| PROGRAM error program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'PROGRAM' in program configuration."); yyerrok;} -| PROGRAM RETAIN error program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive program configuration."); yyerrok;} -| PROGRAM NON_RETAIN error program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive program configuration."); yyerrok;} -| PROGRAM optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no program name defined in program configuration."); yynerrs++;} -| PROGRAM RETAIN optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no program name defined in retentive program configuration."); yynerrs++;} -| PROGRAM NON_RETAIN optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no program name defined in non-retentive program configuration."); yynerrs++;} -| PROGRAM error optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid program name defined in program configuration."); yyerrok;} -| PROGRAM RETAIN error optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid program name defined in retentive program configuration."); yyerrok;} -| PROGRAM NON_RETAIN error optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid program name defined in non-retentive program configuration."); yyerrok;} -| PROGRAM program_name optional_task_name prev_declared_program_type_name optional_prog_conf_elements - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "':' missing after program name or optional task name in program configuration."); yynerrs++;} -| PROGRAM RETAIN program_name optional_task_name prev_declared_program_type_name optional_prog_conf_elements - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':' missing after program name or optional task name in retentive program configuration."); yynerrs++;} -| PROGRAM NON_RETAIN program_name optional_task_name prev_declared_program_type_name optional_prog_conf_elements - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':' missing after program name or optional task name in non-retentive program configuration."); yynerrs++;} -| PROGRAM program_name optional_task_name ':' optional_prog_conf_elements - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no program type defined in program configuration."); yynerrs++;} -| PROGRAM RETAIN program_name optional_task_name ':' optional_prog_conf_elements - {$$ = NULL; print_err_msg(locl(@5), locf(@6), "no program type defined in retentive program configuration."); yynerrs++;} -| PROGRAM NON_RETAIN program_name optional_task_name ':' optional_prog_conf_elements - {$$ = NULL; print_err_msg(locl(@5), locf(@6), "no program type defined in non-retentive program configuration."); yynerrs++;} -/* ERROR_CHECK_END */ -; - -// helper symbol for program_configuration // -optional_task_name: - // empty // - {$$ = NULL;} -| WITH task_name - {$$ = $2;} -/* ERROR_CHECK_BEGIN */ -| WITH error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no task name defined in optional task name of program configuration.");} - else {print_err_msg(locf(@2), locl(@2), "invalid task name in optional task name of program configuration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -// helper symbol for program_configuration // -optional_prog_conf_elements: - // empty // - {$$ = NULL;} -| '(' prog_conf_elements ')' - {$$ = $2;} -/* ERROR_CHECK_BEGIN */ -| '(' error ')' - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid program configuration elements in program configuration."); yyerrok;} -| '(' prog_conf_elements error - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of program configuration elements in program configuration."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -prog_conf_elements: - prog_conf_element - {$$ = new prog_conf_elements_c(locloc(@$)); $$->add_element($1);} -| prog_conf_elements ',' prog_conf_element - {$$ = $1; $$->add_element($3);} -/* ERROR_CHECK_BEGIN */ -| prog_conf_elements prog_conf_element - {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in program configuration elements list."); yynerrs++;} -| prog_conf_elements ',' error - {$$ = $1; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for program configuration element in program configuration list.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value for program configuration element in program configuration list."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -prog_conf_element: - fb_task -| prog_cnxn -; - - -fb_task: - // fb_name WITH task_name -/* NOTE: The fb_name refers to funtion block variables - * that have been declared in a scope outside the one we are - * currently parsing, so we must accept them to be any_identifier! - */ - any_identifier WITH task_name - {$$ = new fb_task_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| any_identifier WITH error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no task name defined in function block configuration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid task name in function block configuration."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -/* NOTE: - * The semantics of configuring a program are rather confusing, so here is - * my (Mario) understanding on the issue... - * - * A function/program may have as its input variables a simple variable - * (BYTE, WORD, etc...), an array (ARRAY [1 .. 3] OF BYTE, ...) , or a structure. - * Nevertheless, when calling this function from within a st or il language statement - * it is not possible to allocate a value to a single element of the array or structure - * typed input variable, as the accepted syntax is simply '(' variable_name ':=' variable ')' - * Notice how the variable_name does not include things such as 'a.elem1' or 'a[1]'! - * - * Nevertheless, when configuring a program from within a configuration, - * it becomes possible to allocate values to individual elements of the - * array or structured type input variable, as the syntax is now - * '(' symbolic_variable ':=' data_sink|prog_data_source ')' - * Notice how the symbolic_variable _does_ include things such as 'a.elem1' or 'a[1]'! - * - * Conclusion: Unlike other locations in the syntax where SENDTO appears, - * here it is not valid to replace symbolic_variable with any_identifier! - * Nevertheless, it is also not correct to leave symbolic_variable as it is, - * as we have defined it to only include previously declared variables, - * which is not the case in this situation. Here symbolic_variable is refering - * to variables that were defined within the scope of the program that is being - * called, and _not_ within the scope of the configuration that is calling the - * program, so the variables in question are not declared in the current scope! - * - * We therefore need to define a new symbolic_variable, that accepts any_identifier - * instead of previosuly declared variable names, to be used in the definition of - * prog_cnxn! - */ -prog_cnxn: - any_symbolic_variable ASSIGN prog_data_source - {$$ = new prog_cnxn_assign_c($1, $3, locloc(@$));} -| any_symbolic_variable SENDTO data_sink - {$$ = new prog_cnxn_sendto_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| any_symbolic_variable constant - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing between parameter and value in program configuration element."); yynerrs++;} -| any_symbolic_variable enumerated_value - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing between parameter and value in program configuration element."); yynerrs++;} -| any_symbolic_variable data_sink - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' or '=>' missing between parameter and variable in program configuration element."); yynerrs++;} -| any_symbolic_variable ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value or variable defined in program configuration assignment element.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value or variable in program configuration assignment element."); yyclearin;} - yyerrok; - } -| any_symbolic_variable SENDTO error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no variable defined in program configuration sendto element.");} - else {print_err_msg(locf(@3), locl(@3), "invalid variable in program configuration sendto element."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -prog_data_source: - constant -| enumerated_value -| global_var_reference -| prev_declared_direct_variable -; - -data_sink: - global_var_reference -| prev_declared_direct_variable -; - -instance_specific_initializations: - VAR_CONFIG instance_specific_init_list END_VAR - {$$ = new instance_specific_initializations_c($2, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| VAR_CONFIG END_VAR - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in configuration variable(s) initialization."); yynerrs++;} -| VAR_CONFIG error instance_specific_init_list END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_CONFIG' in configuration variable(s) initialization."); yyerrok;} -| VAR_CONFIG instance_specific_init_list error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed configuration variable(s) initialization."); yyerrok;} -| VAR_CONFIG error END_VAR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in configuration variable(s) initialization."); yyerrok;} -/* ERROR_CHECK_END */ -; - -// helper symbol for instance_specific_initializations // -instance_specific_init_list: - instance_specific_init ';' - {$$ = new instance_specific_init_list_c(locloc(@$)); $$->add_element($1);} -| instance_specific_init_list instance_specific_init ';' - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| error ';' - {$$ = new instance_specific_init_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid configuration variable initialization."); yyerrok;} -| instance_specific_init error - {$$ = new instance_specific_init_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at the end of configuration variable initialization."); yyerrok;} -| instance_specific_init_list instance_specific_init error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of configuration variable initialization."); yyerrok;} -| instance_specific_init_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid configuration variable initialization."); yyerrok;} -| instance_specific_init_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after configuration variable initialization."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -instance_specific_init: -// -// resource_name '.' program_name '.' {fb_name '.'} -// ((variable_name [location] ':' located_var_spec_init) | (fb_name ':' function_block_type_name ':=' structure_initialization)) -// -// prev_declared_resource_name '.' prev_declared_program_name '.' any_fb_name_list variable_name ':' located_var_spec_init -/* NOTE: variable_name has been changed to any_identifier (and not simply identifier) because the - * variables being referenced have been declared outside the scope currently being parsed! - */ -/* NOTE: program_name has not been changed to prev_declared_program_name because the - * programs being referenced have been declared outside the scope currently being parsed! - * The programs are only kept inside the scope of the resource in which they are defined. - */ - prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier ':' located_var_spec_init - {$$ = new instance_specific_init_c($1, $3, $5, $6, NULL, $8, locloc(@$));} -| prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier location ':' located_var_spec_init - {$$ = new instance_specific_init_c($1, $3, $5, $6, $7, $9, locloc(@$));} -| prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier ':' fb_initialization - {$5->add_element($6); $$ = new instance_specific_init_c($1, $3, $5, NULL, NULL, $8, locloc(@$));} -; - - -/* helper symbol for instance_specific_init */ -fb_initialization: - function_block_type_name ASSIGN structure_initialization - {$$ = new fb_initialization_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| function_block_type_name structure_initialization - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing between function block name and initialization in function block initialization."); yynerrs++;} -| function_block_type_name ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in function block initialization.");} - else {print_err_msg(locf(@3), locl(@3), "invalid initial value in function block initialization."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -/***********************************/ -/* B 2.1 Instructions and Operands */ -/***********************************/ -/* helper symbol for many IL instructions, etc... */ -/* eat up any extra EOL tokens... */ - -eol_list: - EOL -| eol_list EOL -; - - - -instruction_list: - il_instruction - {$$ = new instruction_list_c(locloc(@$)); $$->add_element($1);} -| any_pragma eol_list - {$$ = new instruction_list_c(locloc(@$)); $$->add_element($1);} -| instruction_list il_instruction - {$$ = $1; $$->add_element($2);} -| instruction_list any_pragma - {$$ = $1; $$->add_element($2);} -; - - - -il_instruction: - il_incomplete_instruction eol_list - {$$ = new il_instruction_c(NULL, $1, locloc(@$));} -| label ':' il_incomplete_instruction eol_list - {$$ = new il_instruction_c($1, $3, locloc(@$));} -| label ':' eol_list - {$$ = new il_instruction_c($1, NULL, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| error eol_list - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid IL instruction."); yyerrok;} -| il_incomplete_instruction error - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing at the end of IL instruction."); yyerrok;} -| error ':' il_incomplete_instruction eol_list - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid label in IL instruction."); yyerrok;} -| label il_incomplete_instruction eol_list - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after label in IL instruction."); yynerrs++;} -| label ':' error eol_list - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid IL instruction."); yyerrok;} -| label ':' il_incomplete_instruction error - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "EOL missing at the end of IL instruction."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -/* helper symbol for il_instruction */ -il_incomplete_instruction: - il_simple_operation -| il_expression -| il_jump_operation -| il_fb_call -| il_formal_funct_call -| il_return_operator -; - - -label: identifier; - - - -il_simple_operation: -// (il_simple_operator [il_operand]) | (function_name [il_operand_list]) - il_simple_operator - {$$ = new il_simple_operation_c($1, NULL, locloc(@$));} -/* - * Note: Bison is getting confused with the following rule, - * i.e. it is finding conflicts where there seemingly are really none. - * The rule was therefore replaced by the equivalent following - * two rules. - */ -/* -| il_simple_operator il_operand - {$$ = new il_simple_operation_c($1, $2, locloc(@$));} -*/ -| il_simple_operator_noclash il_operand - {$$ = new il_simple_operation_c($1, $2, locloc(@$));} -| il_simple_operator_clash il_operand - {$$ = new il_simple_operation_c($1, $2, locloc(@$));} -/* NOTE: the line - * | il_simple_operator - * already contains the 'NOT' operator, as well as all the - * expression operators ('MOD', 'AND', etc...), all of which - * may also be a function name! This means that these operators/functions, - * without any operands, could be reduced to either an operator or a - * function call. - * - * I (Mario) have chosen to reduce it to an operator. - * In order to do this, we must remove from the syntax that defines - * function calls all the functions whose names clash with the IL operators. - * - * The line - * | function_name - * has been replaced with the lines - * | function_name_no_clashes - * in order to include all possible function names except - * those whose names coincide with operators !! - */ -| function_name_no_clashes - {$$ = new il_function_call_c($1, NULL, locloc(@$));} -/* NOTE: the line - * | il_simple_operator il_operand - * already contains the 'NOT', 'MOD', etc. operators, followed by a single il_operand. - * However, this same code (MOD x) may also be reduced to a function call to the MOD - * function. This means that (MOD, AND,...) could be interpret as a function name - * or as an IL operator! This would lead us to a reduce/reduce conflict! - * - * I (Mario) have chosen to reduce it to an operand, rather than a function call. - * In order to do this, we must remove from the syntax that defines - * function calls all the functions whose names clash with the IL operators. - * - * The line - * | function_name il_operand_list - * has been replaced with the line - * | function_name_no_clashes il_operand_list - * in order to include all possible function names except - * for the function names which clash with expression and simple operators. - * - * Note that: - * this alternative syntax does not cover the possibility of - * the function 'NOT', 'MOD', etc... being called with more than one il_operand, - * in which case it is always a function call, and not an IL instruction. - * We therefore need to include an extra rule where the - * function_name_expression_clashes and function_name_simpleop_clashes - * are followed by a il_operand_list with __two__ or more il_operands!! - */ -| function_name_no_clashes il_operand_list - {$$ = new il_function_call_c($1, $2, locloc(@$));} -| il_simple_operator_clash il_operand_list2 - {$$ = new il_function_call_c(il_operator_c_2_identifier_c($1), $2, locloc(@$));} -; - - - -il_expression: -// il_expr_operator '(' [il_operand] EOL {EOL} [simple_instr_list] ')' -/* - * Note: Bison is getting confused with the use of il_expr_operator, - * i.e. it is finding conflicts where there seemingly are really none. - * il_expr_operator was therefore replaced by the equivalent - * il_expr_operator_noclash | il_expr_operator_clash. - */ - il_expr_operator_noclash '(' eol_list ')' - {$$ = new il_expression_c($1, NULL, NULL, locloc(@$));} -| il_expr_operator_noclash '(' il_operand eol_list ')' - {$$ = new il_expression_c($1, $3, NULL, locloc(@$));} -| il_expr_operator_noclash '(' eol_list simple_instr_list ')' - {$$ = new il_expression_c($1, NULL, $4, locloc(@$));} -| il_expr_operator_noclash '(' il_operand eol_list simple_instr_list ')' - {$$ = new il_expression_c($1, $3, $5, locloc(@$));} -| il_expr_operator_clash '(' eol_list ')' - {$$ = new il_expression_c($1, NULL, NULL, locloc(@$));} -| il_expr_operator_clash '(' il_operand eol_list ')' - {$$ = new il_expression_c($1, $3, NULL, locloc(@$));} -| il_expr_operator_clash '(' il_operand eol_list simple_instr_list ')' - {$$ = new il_expression_c($1, $3, $5, locloc(@$));} -| il_expr_operator_clash_eol_list simple_instr_list ')' - {$$ = new il_expression_c($1, NULL, $2, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| il_expr_operator_noclash '(' eol_list error - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of IL expression."); yyerrok;} -| il_expr_operator_noclash '(' il_operand eol_list error - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL expression."); yyerrok;} -| il_expr_operator_noclash '(' eol_list simple_instr_list error - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL expression."); yyerrok;} -| il_expr_operator_noclash '(' il_operand eol_list simple_instr_list error - {$$ = NULL; print_err_msg(locl(@5), locf(@6), "')' missing at the end of IL expression."); yyerrok;} -| il_expr_operator_clash '(' il_operand eol_list error - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL expression."); yyerrok;} -| il_expr_operator_clash '(' il_operand eol_list simple_instr_list error - {$$ = NULL; print_err_msg(locl(@5), locf(@6), "')' missing at the end of IL expression."); yyerrok;} -| il_expr_operator_clash_eol_list simple_instr_list error - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of IL expression."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -il_jump_operation: - il_jump_operator label - {$$ = new il_jump_operation_c($1, $2, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| il_jump_operator error - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid label defined in IL jump operation."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -il_fb_call: -// il_call_operator fb_name ['(' (EOL {EOL} [il_param_list]) | [il_operand_list] ')'] - il_call_operator prev_declared_fb_name - {$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));} -| il_call_operator prev_declared_fb_name '(' ')' - {$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));} -| il_call_operator prev_declared_fb_name '(' eol_list ')' - {$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));} -| il_call_operator prev_declared_fb_name '(' il_operand_list ')' - {$$ = new il_fb_call_c($1, $2, $4, NULL, locloc(@$));} -| il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')' - {$$ = new il_fb_call_c($1, $2, NULL, $5, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| il_call_operator error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call.");} - else {print_err_msg(locf(@2), locl(@2), "invalid function block name in IL function block call."); yyclearin;} - yyerrok; - } -| il_call_operator '(' ')' - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} -| il_call_operator '(' eol_list ')' - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} -| il_call_operator '(' il_operand_list ')' - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} -| il_call_operator '(' eol_list il_param_list ')' - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} -| il_call_operator error '(' ')' - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} -| il_call_operator error '(' eol_list ')' - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} -| il_call_operator error '(' il_operand_list ')' - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} -| il_call_operator error '(' eol_list il_param_list ')' - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} -| il_call_operator prev_declared_fb_name ')' - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'(' missing after function block name defined in IL function block call."); yynerrs++;} -| il_call_operator prev_declared_fb_name il_operand_list ')' - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'(' missing after function block name defined in IL function block call."); yynerrs++;} -| il_call_operator prev_declared_fb_name '(' error - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of IL function block call."); yyerrok;} -| il_call_operator prev_declared_fb_name '(' eol_list error - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL function block call."); yyerrok;} -| il_call_operator prev_declared_fb_name '(' il_operand_list error - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL function block call."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -/* NOTE: Please read note above the definition of function_name_without_clashes */ -il_formal_funct_call: -// function_name '(' EOL {EOL} [il_param_list] ')' -/* function_name '(' eol_list ')' */ -/* NOTE: il_formal_funct_call is only used in the definition of - * - il_incomplete_instruction - * - il_simple_instruction - * In both of the above, il_expression also - * shows up as another option. This means that the functions whose - * names clash with expressions, followed by '(' eol_list ')', are - * already included. We must therefore leave them out in this - * definition in order to remove reduce/reduce conflicts. - * - * In summary: 'MOD' '(' eol_list ')', and all other functions whose - * names clash with expressions may be interpreted by the syntax by - * two different routes. I (Mario) chose to interpret them - * as operators, rather than as function calls! - * (AND MOD OR XOR ADD DIV EQ GT GE LT LE MUL NE SUB) - */ - function_name_no_clashes '(' eol_list ')' - {$$ = new il_formal_funct_call_c($1, NULL, locloc(@$));} -| function_name_simpleop_clashes '(' eol_list ')' - {$$ = new il_formal_funct_call_c($1, NULL, locloc(@$));} -/* | function_name '(' eol_list il_param_list ')' */ -/* For the above syntax, we no longer have two ways of interpreting the - * same syntax. The above is always a function call! - * However, some of the functions that we may be calling - * may have the same name as an IL operator. This means that - * flex will be parsing them and handing them over to bison as - * IL operator tokens, and not as function name tokens. - * (when parsing ST, flex no longer recognizes IL operators, - * so will always return the correct function name, unless that - * name also coincides with an operator used in ST -> XOR, OR, MOD, AND, NOT) - * - * We must therefore interpret the IL operators as function names! - */ -| function_name_no_clashes '(' eol_list il_param_list ')' - {$$ = new il_formal_funct_call_c($1, $4, locloc(@$));} -| function_name_simpleop_clashes '(' eol_list il_param_list ')' - {$$ = new il_formal_funct_call_c($1, $4, locloc(@$));} -/* The following line should read: - * - * | function_name_expression_clashes '(' eol_list il_param_list ')' - * - * but the function_name_expression_clashes had to be first reduced to - * an intermediary symbol in order to remove a reduce/reduce conflict. - * In essence, the syntax requires more than one look ahead token - * in order to be parsed. We resolve this by reducing a collection of - * symbols into a temporary symbol (il_expr_operator_clash_eol_list), that - * will later be replaced by the correct symbol. The correct symbol will - * now be determined by a single look ahead token, as all the common - * symbols have been reduced to the temporary symbol - * il_expr_operator_clash_eol_list ! - * - * Unfortunately, this work around results in the wrong symbol - * being created for the abstract syntax tree. - * We need to figure out which symbol was created, destroy it, - * and create the correct symbol for our case. - * This is a lot of work, so I put it in a function - * at the end of this file... il_operator_c_2_identifier_c() - */ -| il_expr_operator_clash_eol_list il_param_list ')' - {$$ = new il_formal_funct_call_c(il_operator_c_2_identifier_c($1), $2, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| function_name_no_clashes '(' eol_list error ')' - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid parameter list defined in IL formal function call."); yyerrok;} -| function_name_simpleop_clashes '(' eol_list error ')' - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid parameter list defined in IL formal function call."); yyerrok;} -| il_expr_operator_clash_eol_list error ')' - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid parameter list defined in IL formal function call."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -il_expr_operator_clash_eol_list: - il_expr_operator_clash '(' eol_list - {$$ = $1;} -/* ERROR_CHECK_BEGIN */ -| il_expr_operator_clash '(' error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "EOL missing after '(' in IL instruction."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -il_operand: - variable -| enumerated_value -| constant -; - - -il_operand_list: - il_operand - {$$ = new il_operand_list_c(locloc(@$)); $$->add_element($1);} -| il_operand_list2 -; - - -/* List with 2 or more il_operands */ -il_operand_list2: - il_operand ',' il_operand - {$$ = new il_operand_list_c(locloc(@$)); $$->add_element($1); $$->add_element($3);} -| il_operand_list2 ',' il_operand - {$$ = $1; $$->add_element($3);} -/* ERROR_CHECK_BEGIN */ -| il_operand_list2 il_operand - {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in IL operand list."); yynerrs++;} -| il_operand ',' error - {$$ = new il_operand_list_c(locloc(@$)); - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no operand defined in IL operand list.");} - else {print_err_msg(locf(@3), locl(@3), "invalid operand name in IL operand list."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -simple_instr_list: - il_simple_instruction - {$$ = new simple_instr_list_c(locloc(@$)); $$->add_element($1);} -| simple_instr_list il_simple_instruction - {$$ = $1; $$->add_element($2);} -; - - -il_simple_instruction: - il_simple_operation eol_list -| il_expression eol_list -| il_formal_funct_call eol_list -/* ERROR_CHECK_BEGIN */ -| il_expression error - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing after expression IL instruction."); yyerrok;} -| il_formal_funct_call error - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing after formal function call IL instruction."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -/* NOTE: the correct definition of il_param_list is - * il_param_list ::= {il_param_instruction} il_param_last_instruction - * - * where {...} denotes zero or many il_param_instruction's. - * - * We could do this by defining the following: - * il_param_list: il_param_instruction_list il_param_last_instruction; - * il_param_instruction_list : ** empty ** | il_param_instruction_list il_param_instruction; - * - * Unfortunately, the above leads to reduce/reduce conflicts. - * The chosen alternative (as follows) does not have any conflicts! - * il_param_list: il_param_last_instruction | il_param_instruction_list il_param_last_instruction; - * il_param_instruction_list : il_param_instruction_list | il_param_instruction_list il_param_instruction; - */ -il_param_list: - il_param_instruction_list il_param_last_instruction - {$$ = $1; $$->add_element($2);} -| il_param_last_instruction - {$$ = new il_param_list_c(locloc(@$)); $$->add_element($1);} -/* ERROR_CHECK_BEGIN */ -| il_param_instruction_list error - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid parameter assignment in parameter assignment list."); yyerrok;} -| il_param_last_instruction il_param_last_instruction - {$$ = new il_param_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "',' missing at the end of parameter assignment in parameter assignment list."); yynerrs++;} -| il_param_instruction_list il_param_last_instruction il_param_last_instruction - {$$ = $1; print_err_msg(locl(@2), locf(@3), "',' missing at the end of parameter assignment in parameter assignment list."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -/* Helper symbol for il_param_list */ -il_param_instruction_list: - il_param_instruction - {$$ = new il_param_list_c(locloc(@$)); $$->add_element($1);} -| il_param_instruction_list il_param_instruction - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| il_param_last_instruction il_param_instruction - {$$ = new il_param_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "',' missing at the end of parameter assignment in parameter assignment list."); yynerrs++;} -| il_param_instruction_list il_param_last_instruction il_param_instruction - {$$ = $1; print_err_msg(locl(@2), locf(@3), "',' missing at the end of parameter assignment in parameter assignment list."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -il_param_instruction: - il_param_assignment ',' eol_list -| il_param_out_assignment ',' eol_list -/* ERROR_CHECK_BEGIN */ -| il_param_assignment ',' error - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "EOL missing at the end of parameter assignment in parameter assignment list."); yyerrok;} -| il_param_out_assignment ',' error - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "EOL missing at the end of parameter out assignment in parameter assignment list."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -il_param_last_instruction: - il_param_assignment eol_list -| il_param_out_assignment eol_list -/* ERROR_CHECK_BEGIN */ -| il_param_assignment error - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing at the end of last parameter assignment in parameter assignment list."); yyerrok;} -| il_param_out_assignment error - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing at the end of last parameter out assignment in parameter assignment list."); yyerrok;} -/* ERROR_CHECK_END */ - -; - - -il_param_assignment: - il_assign_operator il_operand - {$$ = new il_param_assignment_c($1, $2, NULL, locloc(@$));} -| il_assign_operator '(' eol_list simple_instr_list ')' - {$$ = new il_param_assignment_c($1, NULL, $4, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| error il_operand - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid operator in parameter assignment."); yyerrok;} -| error '(' eol_list simple_instr_list ')' - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid operator in parameter assignment."); yyerrok;} -| il_assign_operator error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no operand defined in parameter assignment.");} - else {print_err_msg(locf(@2), locl(@2), "invalid operand in parameter assignment."); yyclearin;} - yyerrok; - } -| il_assign_operator '(' eol_list ')' - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no instruction list defined in parameter assignment."); yynerrs++;} -| il_assign_operator '(' eol_list error ')' - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid instruction list defined in parameter assignment."); yyerrok;} -| il_assign_operator '(' eol_list simple_instr_list error - {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of instruction list defined in parameter assignment."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -il_param_out_assignment: - il_assign_out_operator variable - {$$ = new il_param_out_assignment_c($1, $2, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| il_assign_out_operator error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no variable defined in IL operand list.");} - else {print_err_msg(locf(@2), locl(@2), "invalid variable in IL operand list."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - - -/*******************/ -/* B 2.2 Operators */ -/*******************/ -sendto_identifier: sendto_identifier_token {$$ = new identifier_c($1, locloc(@$));}; - - -/* NOTE: - * The spec includes the operator 'EQ ' - * Note that EQ is followed by a space. - * I am considering this a typo, and defining the operator - * as 'EQ' - * (Mario) - */ -LD_operator: LD {$$ = new LD_operator_c(locloc(@$));}; -LDN_operator: LDN {$$ = new LDN_operator_c(locloc(@$));}; -ST_operator: ST {$$ = new ST_operator_c(locloc(@$));}; -STN_operator: STN {$$ = new STN_operator_c(locloc(@$));}; -NOT_operator: NOT {$$ = new NOT_operator_c(locloc(@$));}; -S_operator: S {$$ = new S_operator_c(locloc(@$));}; -R_operator: R {$$ = new R_operator_c(locloc(@$));}; -S1_operator: S1 {$$ = new S1_operator_c(locloc(@$));}; -R1_operator: R1 {$$ = new R1_operator_c(locloc(@$));}; -CLK_operator: CLK {$$ = new CLK_operator_c(locloc(@$));}; -CU_operator: CU {$$ = new CU_operator_c(locloc(@$));}; -CD_operator: CD {$$ = new CD_operator_c(locloc(@$));}; -PV_operator: PV {$$ = new PV_operator_c(locloc(@$));}; -IN_operator: IN {$$ = new IN_operator_c(locloc(@$));}; -PT_operator: PT {$$ = new PT_operator_c(locloc(@$));}; -AND_operator: AND {$$ = new AND_operator_c(locloc(@$));}; -AND2_operator: AND2 {$$ = new AND_operator_c(locloc(@$));}; /* '&' in the source code! */ -OR_operator: OR {$$ = new OR_operator_c(locloc(@$));}; -XOR_operator: XOR {$$ = new XOR_operator_c(locloc(@$));}; -ANDN_operator: ANDN {$$ = new ANDN_operator_c(locloc(@$));}; -ANDN2_operator: ANDN2 {$$ = new ANDN_operator_c(locloc(@$));}; /* '&N' in the source code! */ -ORN_operator: ORN {$$ = new ORN_operator_c(locloc(@$));}; -XORN_operator: XORN {$$ = new XORN_operator_c(locloc(@$));}; -ADD_operator: ADD {$$ = new ADD_operator_c(locloc(@$));}; -SUB_operator: SUB {$$ = new SUB_operator_c(locloc(@$));}; -MUL_operator: MUL {$$ = new MUL_operator_c(locloc(@$));}; -DIV_operator: DIV {$$ = new DIV_operator_c(locloc(@$));}; -MOD_operator: MOD {$$ = new MOD_operator_c(locloc(@$));}; -GT_operator: GT {$$ = new GT_operator_c(locloc(@$));}; -GE_operator: GE {$$ = new GE_operator_c(locloc(@$));}; -EQ_operator: EQ {$$ = new EQ_operator_c(locloc(@$));}; -LT_operator: LT {$$ = new LT_operator_c(locloc(@$));}; -LE_operator: LE {$$ = new LE_operator_c(locloc(@$));}; -NE_operator: NE {$$ = new NE_operator_c(locloc(@$));}; -CAL_operator: CAL {$$ = new CAL_operator_c(locloc(@$));}; -CALC_operator: CALC {$$ = new CALC_operator_c(locloc(@$));}; -CALCN_operator: CALCN {$$ = new CALCN_operator_c(locloc(@$));}; -RET_operator: RET {$$ = new RET_operator_c(locloc(@$));}; -RETC_operator: RETC {$$ = new RETC_operator_c(locloc(@$));}; -RETCN_operator: RETCN {$$ = new RETCN_operator_c(locloc(@$));}; -JMP_operator: JMP {$$ = new JMP_operator_c(locloc(@$));}; -JMPC_operator: JMPC {$$ = new JMPC_operator_c(locloc(@$));}; -JMPCN_operator: JMPCN {$$ = new JMPCN_operator_c(locloc(@$));}; - - -il_simple_operator: - il_simple_operator_clash -| il_simple_operator_noclash -; - - -il_simple_operator_noclash: - LD_operator -| LDN_operator -| ST_operator -| STN_operator -| S_operator -| R_operator -| S1_operator -| R1_operator -| CLK_operator -| CU_operator -| CD_operator -| PV_operator -| IN_operator -| PT_operator -| il_expr_operator_noclash -; - - -il_simple_operator_clash: - il_simple_operator_clash1 -| il_simple_operator_clash2 -; - -il_simple_operator_clash1: - NOT_operator -; - -il_simple_operator_clash2: - il_expr_operator_clash -; - - -/* -il_expr_operator: - il_expr_operator_noclash -| il_expr_operator_clash -; -*/ - -il_expr_operator_clash: - AND_operator -| OR_operator -| XOR_operator -| ADD_operator -| SUB_operator -| MUL_operator -| DIV_operator -| MOD_operator -| GT_operator -| GE_operator -| EQ_operator -| LT_operator -| LE_operator -| NE_operator -; - - -il_expr_operator_noclash: - ANDN_operator -| ANDN2_operator /* string '&N' in source code! */ -| AND2_operator /* string '&' in source code! */ -| ORN_operator -| XORN_operator -; - - - - -il_assign_operator: -/* variable_name ASSIGN */ - any_identifier ASSIGN - {$$ = new il_assign_operator_c($1, locloc(@$));} -| en_identifier ASSIGN - {$$ = new il_assign_operator_c($1, locloc(@$));} -| S1_operator ASSIGN - {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} -| R1_operator ASSIGN - {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} -| CLK_operator ASSIGN - {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} -| CU_operator ASSIGN - {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} -| CD_operator ASSIGN - {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} -| PV_operator ASSIGN - {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} -| IN_operator ASSIGN - {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} -| PT_operator ASSIGN - {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| error ASSIGN - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid parameter defined in parameter assignment."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -il_assign_out_operator: -/* variable_name SENDTO */ -/* any_identifier SENDTO */ - sendto_identifier SENDTO - {$$ = new il_assign_out_operator_c(NULL, $1, locloc(@$));} -/* The following is not required, as the sendto_identifier_token returned by flex will - * also include the 'ENO' identifier. - * The resulting abstract syntax tree is identical with or without this following rule, - * as both the eno_identifier and the sendto_identifier are stored as - * an identifier_c !! - * - * To understand why we must even explicitly consider the use of ENO here, - * please read the comment above the definition of 'variable' in section B1.4 for details. - */ -/* -| eno_identifier SENDTO - {$$ = new il_assign_out_operator_c(NULL, $1, locloc(@$));} -*/ -/*| NOT variable_name SENDTO */ -| NOT sendto_identifier SENDTO - {$$ = new il_assign_out_operator_c(new not_paramassign_c(locloc(@1)), $2, locloc(@$));} -/* The following is not required, as the sendto_identifier_token returned by flex will - * also include the 'ENO' identifier. - * The resulting abstract syntax tree is identical with or without this following rule, - * as both the eno_identifier and the sendto_identifier are stored as - * an identifier_c !! - * - * To understand why we must even explicitly consider the use of ENO here, - * please read the comment above the definition of 'variable' in section B1.4 for details. - * - * NOTE: Removing the following rule also removes a shift/reduce conflict from the parser. - * This conflict is not really an error/ambiguity in the syntax, but rather - * due to the fact that more than a single look-ahead token would be required - * to correctly parse the syntax, something that bison does not support. - * - * The shift/reduce conflict arises because bison does not know whether - * to parse the 'NOT ENO' in the following code - * LD 1 - * funct_name ( - * NOT ENO => bool_var, - * EN := TRUE - * ) - * as either a il_param_assignment (wrong!) or an il_param_out_assignment.(correct). - * The '=>' delimiter (known as SEND_TO in this iec.y file) is a dead giveaway that - * it should be parsed as an il_param_out_assignment, but still, bison gets confused! - * Bison considers the possibility of reducing the 'NOT ENO' as an NOT_operator with - * the 'ENO' operand - * (NOT_operator -> il_simple_operator -> il_simple_operation -> il_simple_instruction -> - * -> simple_instr_list -> il_param_assignment) - * instead of reducing it to an il_param_out_operator. - * ( il_param_out_operator -> il_param_out_assignment) - * - * Note that the shift/reduce conflict only manifests itself in the il_formal_funct_call, - * where both the il_param_out_assignment and il_param_assignment are used! - * - * il_param_out_assignment --+--> il_param_instruction -> il_param_instruction_list --+ - * | | - * il_param_assignment --+ | - * | - * il_formal_funct_call <- il_param_list <-+ - * - */ -/* -| NOT eno_identifier SENDTO - {$$ = new il_assign_out_operator_c(new not_paramassign_c(locloc(@1)), $2, locloc(@$));} -*/ -/* ERROR_CHECK_BEGIN */ -| error SENDTO - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid parameter defined in parameter out assignment."); yyerrok;} -| NOT SENDTO - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no parameter defined in parameter out assignment."); yynerrs++;} -| NOT error SENDTO - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid parameter defined in parameter out assignment."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -il_call_operator: - CAL_operator -| CALC_operator -| CALCN_operator -; - - -il_return_operator: - RET_operator -| RETC_operator -| RETCN_operator -; - - -il_jump_operator: - JMP_operator -| JMPC_operator -| JMPCN_operator -; - - -/***********************/ -/* B 3.1 - Expressions */ -/***********************/ -expression: - xor_expression -| expression OR xor_expression - {$$ = new or_expression_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| expression OR error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'OR' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'OR' in ST expression."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -xor_expression: - and_expression -| xor_expression XOR and_expression - {$$ = new xor_expression_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| xor_expression XOR error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'XOR' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'XOR' in ST expression."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -and_expression: - comparison -| and_expression '&' comparison - {$$ = new and_expression_c($1, $3, locloc(@$));} -| and_expression AND comparison - {$$ = new and_expression_c($1, $3, locloc(@$));} -/* NOTE: The lexical parser never returns the token '&'. - * The '&' string is interpreted by the lexcial parser as the token - * AND2! - * This means that the first rule with '&' is actually not required, - * but we leave it in nevertheless just in case we later decide - * to remove the AND2 token... - */ -| and_expression AND2 comparison - {$$ = new and_expression_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| and_expression '&' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '&' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after '&' in ST expression."); yyclearin;} - yyerrok; - } -| and_expression AND error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'AND' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'AND' in ST expression."); yyclearin;} - yyerrok; - } -| and_expression AND2 error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '&' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after '&' in ST expression."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -comparison: - equ_expression -| comparison '=' equ_expression - {$$ = new equ_expression_c($1, $3, locloc(@$));} -| comparison OPER_NE equ_expression - {$$ = new notequ_expression_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| comparison '=' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '=' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after '=' in ST expression."); yyclearin;} - yyerrok; - } -| comparison OPER_NE error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '<>' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after '<>' in ST expression."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -equ_expression: - add_expression -| equ_expression '<' add_expression - {$$ = new lt_expression_c($1, $3, locloc(@$));} -| equ_expression '>' add_expression - {$$ = new gt_expression_c($1, $3, locloc(@$));} -| equ_expression OPER_LE add_expression - {$$ = new le_expression_c($1, $3, locloc(@$));} -| equ_expression OPER_GE add_expression - {$$ = new ge_expression_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| equ_expression '<' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '<' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after '<' in ST expression."); yyclearin;} - yyerrok; - } -| equ_expression '>' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '>' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after '>' in ST expression."); yyclearin;} - yyerrok; - } -| equ_expression OPER_LE error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '<=' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after '<=' in ST expression."); yyclearin;} - yyerrok; - } -| equ_expression OPER_GE error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '>=' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after '>=' in ST expression."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -/* Not required... -comparison_operator: '<' | '>' | '>=' '<=' -*/ - -add_expression: - term -| add_expression '+' term - {$$ = new add_expression_c($1, $3, locloc(@$));} -| add_expression '-' term - {$$ = new sub_expression_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| add_expression '+' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '+' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after '+' in ST expression."); yyclearin;} - yyerrok; - } -| add_expression '-' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '-' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after '-' in ST expression."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -/* Not required... -add_operator: '+' | '-' -*/ - -term: - power_expression -| term '*' power_expression - {$$ = new mul_expression_c($1, $3, locloc(@$));} -| term '/' power_expression - {$$ = new div_expression_c($1, $3, locloc(@$));} -| term MOD power_expression - {$$ = new mod_expression_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| term '*' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '*' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after '*' in ST expression."); yyclearin;} - yyerrok; - } -| term '/' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '/' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after '/' in ST expression."); yyclearin;} - yyerrok; - } -| term MOD error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'MOD' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'MOD' in ST expression."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -/* Not required... -multiply_operator: '*' | '/' | 'MOD' -*/ - -power_expression: - unary_expression -| power_expression OPER_EXP unary_expression - {$$ = new power_expression_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| power_expression OPER_EXP error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '**' in ST expression.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after '**' in ST expression."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -unary_expression: - non_negative_primary_expression -| '-' non_negative_primary_expression - {$$ = new neg_expression_c($2, locloc(@$));} -| NOT primary_expression - {$$ = new not_expression_c($2, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| '-' error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no expression defined after '-' in ST expression.");} - else {print_err_msg(locf(@2), locl(@2), "invalid expression after '-' in ST expression."); yyclearin;} - yyerrok; - } -| NOT error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no expression defined after 'NOT' in ST expression.");} - else {print_err_msg(locf(@2), locl(@2), "invalid expression after 'NOT' in ST expression."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -/* Not required... -unary_operator: '-' | 'NOT' -*/ - - -/* NOTE: using constant as a possible symbol for primary_expression - * leads to a reduce/reduce conflict. - * - * The text '-9' may be parsed as either a - * expression<-primary_expression<-constant<-signed_integer - * (i.e. the constant 9 negative) - * OR - * expression<-unary_expression<-constant<-integer - * (i.e. the constant 9, preceded by a unary negation) - * - * To remove the conflict, we only allow constants without - * a preceding '-' to be used in primary_expression - * (i.e. as a parameter to the unary negation operator) - */ -/* NOTE: We use enumerated_value_without_identifier instead of enumerated_value - * in order to remove a reduce/reduce conflict between reducing an - * identifier to a variable or an enumerated_value. - * - * This change follows the IEC specification. The specification seems to - * imply (by introducing syntax that allows to unambiguosly reference an - * enumerated value - enum_type#enum_value) that in case the same identifier is used - * for a variable and an enumerated value, then the variable shall be - * considered. - */ -non_negative_primary_expression: - non_negative_constant -//| enumerated_value_without_identifier -| enumerated_value -| variable -| '(' expression ')' - {$$ = $2;} -| function_invocation -/* ERROR_CHECK_BEGIN */ -| '(' expression error - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of expression in ST expression."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -primary_expression: - constant -//| enumerated_value_without_identifier -| enumerated_value -| variable -| '(' expression ')' - {$$ = $2;} -| function_invocation -/* ERROR_CHECK_BEGIN */ -| '(' expression error - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of expression in ST expression."); yyerrok;} -/* ERROR_CHECK_END */ -; - - - -/* intermediate helper symbol for primary_expression */ -/* NOTE: function_name includes the standard function name 'NOT' ! - * This introduces a reduce/reduce conflict, as NOT(var) - * may be parsed as either a function_invocation, or a - * unary_expression. - * - * I (Mario) have opted to remove the possible reduction - * to function invocation, which means replacing the rule - * function_name '(' param_assignment_list ')' - * with - * function_name_no_NOT_clashes '(' param_assignment_list ')' - * - * Notice how the new rule does not include the situation where - * the function NOT is called with more than one parameter, which - * the original rule does include! Callinf the NOT function with more - * than one argument is probably a semantic error anyway, so it - * doesn't make much sense to take it into account. - * - * Nevertheless, if we were to to it entirely correctly, - * leaving the semantic checks for the next compiler stage, - * this syntax parser would need to include such a possibility. - * - * We will leave this out for now. No need to complicate the syntax - * more than the specification does by contradicting itself, and - * letting names clash! - */ -function_invocation: -/* function_name '(' [param_assignment_list] ')' */ - function_name_no_NOT_clashes '(' param_assignment_formal_list ')' - {$$ = new function_invocation_c($1, $3, NULL, locloc(@$));} -| function_name_no_NOT_clashes '(' param_assignment_nonformal_list ')' - {$$ = new function_invocation_c($1, NULL, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| function_name_no_NOT_clashes param_assignment_formal_list ')' - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function name in ST expression."); yynerrs++;} -| function_name_no_NOT_clashes '(' ')' - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no parameter defined in function invocation of ST expression."); yynerrs++;} -| function_name_no_NOT_clashes '(' error ')' - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid parameter(s) defined in function invocation of ST expression."); yyerrok;} -| function_name_no_NOT_clashes '(' param_assignment_formal_list error - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of function invocation in ST expression."); yyerrok;} -| function_name_no_NOT_clashes '(' param_assignment_nonformal_list error - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of function invocation in ST expression."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -/********************/ -/* B 3.2 Statements */ -/********************/ -statement_list: - statement ';' - {$$ = new statement_list_c(locloc(@$)); $$->add_element($1);} -| any_pragma - {$$ = new statement_list_c(locloc(@$)); $$->add_element($1);} -| statement_list statement ';' - {$$ = $1; $$->add_element($2);} -| statement_list any_pragma - {$$ = $1; $$->add_element($2);} -/* ERROR_CHECK_BEGIN */ -| statement error - {$$ = new statement_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at the end of statement in ST statement."); yyerrok;} -| statement_list statement error - {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of statement in ST statement."); yyerrok;} -| statement_list error ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid statement in ST statement."); yyerrok;} -| statement_list ';' - {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after statement in ST statement."); yynerrs++;} -/* ERROR_CHECK_END */ -; - - -statement: - assignment_statement -| subprogram_control_statement -| selection_statement -| iteration_statement -; - - -/*********************************/ -/* B 3.2.1 Assignment Statements */ -/*********************************/ -assignment_statement: - variable ASSIGN expression - {$$ = new assignment_statement_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| error ASSIGN expression - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid variable before ':=' in ST assignment statement."); yyerrok;} -| variable ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after ':=' in ST assignment statement.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression after ':=' in ST assignment statement."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - - - -/*****************************************/ -/* B 3.2.2 Subprogram Control Statements */ -/*****************************************/ -subprogram_control_statement: - fb_invocation -| return_statement -; - -return_statement: - RETURN {$$ = new return_statement_c(locloc(@$));} -; - - - -fb_invocation: - prev_declared_fb_name '(' ')' - {$$ = new fb_invocation_c($1, NULL, NULL, locloc(@$)); } -| prev_declared_fb_name '(' param_assignment_formal_list ')' - {$$ = new fb_invocation_c($1, $3, NULL, locloc(@$));} -| prev_declared_fb_name '(' param_assignment_nonformal_list ')' - {$$ = new fb_invocation_c($1, NULL, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| prev_declared_fb_name ')' - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function block name in ST statement."); yynerrs++;} -| prev_declared_fb_name param_assignment_formal_list ')' - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function block name in ST statement."); yynerrs++;} -| prev_declared_fb_name '(' error ')' - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid parameter list in function block invocation in ST statement."); yyerrok;} -| prev_declared_fb_name '(' error - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing after parameter list of function block invocation in ST statement."); yyerrok;} -| prev_declared_fb_name '(' param_assignment_formal_list error - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing after parameter list of function block invocation in ST statement."); yyerrok;} -| prev_declared_fb_name '(' param_assignment_nonformal_list error - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing after parameter list of function block invocation in ST statement."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -/* helper symbol for - * - fb_invocation - * - function_invocation - */ -param_assignment_formal_list: - param_assignment_formal - {$$ = new param_assignment_list_c(locloc(@$)); $$->add_element($1);} -| param_assignment_formal_list ',' param_assignment_formal - {$$ = $1; $$->add_element($3);} -/* ERROR_CHECK_BEGIN */ -| param_assignment_formal_list ',' error - {$$ = $1; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no parameter assignment defined in ST parameter assignment list.");} - else {print_err_msg(locf(@3), locl(@3), "invalid parameter assignment in ST parameter assignment list."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - -/* helper symbol for - * - fb_invocation - * - function_invocation - */ -param_assignment_nonformal_list: - param_assignment_nonformal - {$$ = new param_assignment_list_c(locloc(@$)); $$->add_element($1);} -| param_assignment_nonformal_list ',' param_assignment_nonformal - {$$ = $1; $$->add_element($3);} -/* ERROR_CHECK_BEGIN */ -| param_assignment_nonformal_list ',' error - {$$ = $1; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no parameter assignment defined in ST parameter assignment list.");} - else {print_err_msg(locf(@3), locl(@3), "invalid parameter assignment in ST parameter assignment list."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -/* NOTE: According to the IEC 61131-3 standard, there are two possible - * syntaxes for calling function blocks within ST. - * The formal method has the form: - * fb ( invar := x, inoutvar := var1, outvar => var2); - * The non-formal method has the form: - * fb (x, var1, var2); - * In the text of IEC 61131-3 (where the semantics are defined), - * it is obvious that mixing the two syntaxes is considered incorrect. - * The following should therefore be incorrect: - * fb ( invar := x, var1, var2); - * However, according to the syntax definition, as defined in IEC 61131-3, - * mixing the formal and non-formal methods of invocation is allowed. - * We have two alternatives: - * (a) implement the syntax here in iec.y according to the standard, - * and leave it to the semantic analyser stage to find this error - * (b) or implement the syntax in iec.y correctly, not allowing - * the mixing of formal and non-formal invocation syntaxes. - * Considering that this is a syntax issue, and not semantic issue, - * I (Mario) have decided to go with alternative (a). - * In other words, in iec.y we do not follow the syntax as defined in - * Annex B of the IEC 61131-3 standard, but rather implement - * the syntax also taking into account the textual part of the standard too. - */ -/* -param_assignment: - variable_name ASSIGN expression -*/ -param_assignment_nonformal: - expression -; - - -param_assignment_formal: - any_identifier ASSIGN expression - {$$ = new input_variable_param_assignment_c($1, $3, locloc(@$));} -| en_identifier ASSIGN expression - {$$ = new input_variable_param_assignment_c($1, $3, locloc(@$));} -/*| variable_name SENDTO variable */ -/*| any_identifier SENDTO variable */ -| sendto_identifier SENDTO variable - {$$ = new output_variable_param_assignment_c(NULL, $1, $3, locloc(@$));} -/* The following is not required, as the sendto_identifier_token returned by flex will - * also include the 'ENO' identifier. - * The resulting abstract syntax tree is identical with or without this following rule, - * as both the eno_identifier and the sendto_identifier are stored as - * an identifier_c !! - * - * To understand why we must even explicitly consider the use of ENO here, - * please read the comment above the definition of 'variable' in section B1.4 for details. - */ -/* -| eno_identifier SENDTO variable - {$$ = new output_variable_param_assignment_c(NULL, $1, $3, locloc(@$));} -*/ -/*| NOT variable_name SENDTO variable */ -/*| NOT any_identifier SENDTO variable*/ -| NOT sendto_identifier SENDTO variable - {$$ = new output_variable_param_assignment_c(new not_paramassign_c(locloc(@$)), $2, $4, locloc(@$));} -/* The following is not required, as the sendto_identifier_token returned by flex will - * also include the 'ENO' identifier. - * The resulting abstract syntax tree is identical with or without this following rule, - * as both the eno_identifier and the sendto_identifier are stored as - * an identifier_c !! - * - * To understand why we must even explicitly consider the use of ENO here, - * please read the comment above the definition of 'variable' in section B1.4 for details. - */ -/* -| NOT eno_identifier SENDTO variable - {$$ = new output_variable_param_assignment_c(new not_paramassign_c(locloc(@$)), $2, $4, locloc(@$));} -*/ -/* ERROR_CHECK_BEGIN */ -| any_identifier ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter assignment.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter assignment."); yyclearin;} - yyerrok; - } -| en_identifier ASSIGN error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter assignment.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter assignment."); yyclearin;} - yyerrok; - } -| sendto_identifier SENDTO error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter out assignment.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter out assignment."); yyclearin;} - yyerrok; - } -/* -| eno_identifier SENDTO error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter out assignment.");} - else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter out assignment."); yyclearin;} - yyerrok; - } -*/ -| NOT SENDTO variable - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no parameter name defined in ST formal parameter out negated assignment."); yynerrs++;} -| NOT error SENDTO variable - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid parameter name defined in ST formal parameter out negated assignment."); yyerrok;} -| NOT sendto_identifier SENDTO error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no expression defined in ST formal parameter out negated assignment.");} - else {print_err_msg(locf(@4), locl(@4), "invalid expression in ST formal parameter out negated assignment."); yyclearin;} - yyerrok; - } -/* -| NOT eno_identifier SENDTO error - {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no expression defined in ST formal parameter out negated assignment.");} - else {print_err_msg(locf(@4), locl(@4), "invalid expression in ST formal parameter out negated assignment."); yyclearin;} - yyerrok; - } -*/ -/* ERROR_CHECK_END */ -; - - - - - -/********************************/ -/* B 3.2.3 Selection Statements */ -/********************************/ -selection_statement: - if_statement -| case_statement -; - - -if_statement: - IF expression THEN statement_list elseif_statement_list END_IF - {$$ = new if_statement_c($2, $4, $5, NULL, locloc(@$));} -| IF expression THEN statement_list elseif_statement_list ELSE statement_list END_IF - {$$ = new if_statement_c($2, $4, $5, $7, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| IF THEN statement_list elseif_statement_list END_IF - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'IF' statement."); yynerrs++;} -| IF THEN statement_list elseif_statement_list ELSE statement_list END_IF - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'IF' statement."); yynerrs++;} -| IF error THEN statement_list elseif_statement_list END_IF - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'IF' statement."); yyerrok;} -| IF error THEN statement_list elseif_statement_list ELSE statement_list END_IF - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'IF' statement."); yyerrok;} -| IF expression error statement_list elseif_statement_list END_IF - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'THEN' after test expression in ST 'IF' statement."); yyerrok;} -| IF expression error statement_list elseif_statement_list ELSE statement_list END_IF - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'THEN' after test expression in ST 'IF' statement."); yyerrok;} -| IF expression THEN elseif_statement_list END_IF - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no statement defined after 'THEN' in ST 'IF' statement."); yynerrs++;} -| IF expression THEN elseif_statement_list ELSE statement_list END_IF - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no statement defined after 'THEN' in ST 'IF' statement."); yynerrs++;} -| IF expression THEN statement_list elseif_statement_list ELSE END_IF - {$$ = NULL; print_err_msg(locl(@6), locf(@7), "no statement defined after 'ELSE' in ST 'IF' statement."); yynerrs++;} -| IF expression THEN statement_list elseif_statement_list ELSE error END_IF - {$$ = NULL; print_err_msg(locf(@7), locl(@7), "invalid statement defined after 'ELSE' in ST 'IF' statement."); yynerrs++; yyerrok;} -| IF expression error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed 'IF' statement in ST."); yyerrok;} -| IF expression THEN statement_list elseif_statement_list END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'IF' statement in ST."); yynerrs++;} -| IF expression THEN statement_list elseif_statement_list ELSE statement_list END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'IF' statement in ST."); yynerrs++;} -| IF error END_IF - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'IF' statement."); yyerrok;} -/* ERROR_CHECK_END */ -; - -/* helper symbol for if_statement */ -elseif_statement_list: - /* empty */ - {$$ = new elseif_statement_list_c(locloc(@$));} -| elseif_statement_list elseif_statement - {$$ = $1; $$->add_element($2);} -; - -/* helper symbol for elseif_statement_list */ -elseif_statement: - ELSIF expression THEN statement_list - {$$ = new elseif_statement_c($2, $4, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| ELSIF THEN statement_list - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined for 'ELSEIF' statement in ST 'IF' statement."); yynerrs++;} -| ELSIF error THEN statement_list - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for 'ELSEIF' statement in ST 'IF' statement."); yyerrok;} -| ELSIF expression error statement_list - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'THEN' after test expression in 'ELSEIF' statement of ST 'IF' statement."); yyerrok;} -| ELSIF expression THEN error - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid statement list in 'ELSEIF' statement of ST 'IF' statement."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -case_statement: - CASE expression OF case_element_list END_CASE - {$$ = new case_statement_c($2, $4, NULL, locloc(@$));} -| CASE expression OF case_element_list ELSE statement_list END_CASE - {$$ = new case_statement_c($2, $4, $6, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| CASE OF case_element_list END_CASE - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'CASE' statement."); yynerrs++;} -| CASE OF case_element_list ELSE statement_list END_CASE - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'CASE' statement."); yynerrs++;} -| CASE error OF case_element_list END_CASE - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'CASE' statement."); yyerrok;} -| CASE error OF case_element_list ELSE statement_list END_CASE - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'CASE' statement."); yyerrok;} -| CASE expression error case_element_list END_CASE - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'OF' after test expression in ST 'CASE' statement."); yyerrok;} -| CASE expression error case_element_list ELSE statement_list END_CASE - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'OF' after test expression in ST 'CASE' statement."); yyerrok;} -| CASE expression OF END_CASE - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no case element(s) defined after 'OF' in ST 'CASE' statement."); yynerrs++;} -| CASE expression OF ELSE statement_list END_CASE - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no case element(s) defined after 'OF' in ST 'CASE' statement."); yynerrs++;} -| CASE expression OF error END_CASE - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid case element(s) defined after 'OF' in ST 'CASE' statement."); yyerrok;} -| CASE expression OF error ELSE statement_list END_CASE - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid case element(s) defined after 'OF' in ST 'CASE' statement."); yyerrok;} -| CASE expression OF case_element_list ELSE END_CASE - {$$ = NULL; print_err_msg(locl(@5), locf(@6), "no statement defined after 'ELSE' in ST 'CASE' statement."); yynerrs++;} -| CASE expression OF case_element_list ELSE error END_CASE - {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid statement defined after 'ELSE' in ST 'CASE' statement."); yyerrok;} -| CASE expression error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed 'CASE' statement in ST."); yyerrok;} -| CASE expression OF case_element_list END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'CASE' statement in ST."); yynerrs++;} -| CASE expression OF case_element_list ELSE statement_list END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'CASE' statement in ST."); yynerrs++;} -| CASE error END_CASE - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'CASE' statement."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -/* helper symbol for case_statement */ -case_element_list: - case_element - {$$ = new case_element_list_c(locloc(@$)); $$->add_element($1);} -| case_element_list case_element - {$$ = $1; $$->add_element($2);} -; - - -case_element: - case_list ':' statement_list - {$$ = new case_element_c($1, $3, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| case_list statement_list - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after case list in ST 'CASE' statement."); yynerrs++;} -| case_list ':' error - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid statement in case element of ST 'CASE' statement."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -case_list: - case_list_element - {$$ = new case_list_c(locloc(@$)); $$->add_element($1);} -| case_list ',' case_list_element - {$$ = $1; $$->add_element($3);} -/* ERROR_CHECK_BEGIN */ -| case_list ',' error - {$$ = $1; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no case defined in case list of ST parameter assignment list.");} - else {print_err_msg(locf(@3), locl(@3), "invalid case in case list of ST parameter assignment list."); yyclearin;} - yyerrok; - } -/* ERROR_CHECK_END */ -; - - -case_list_element: - signed_integer -| subrange -| enumerated_value -; - - - - - -/********************************/ -/* B 3.2.4 Iteration Statements */ -/********************************/ -iteration_statement: - for_statement -| while_statement -| repeat_statement -| exit_statement -; - - -for_statement: - FOR control_variable ASSIGN expression TO expression BY expression DO statement_list END_FOR - {$$ = new for_statement_c($2, $4, $6, $8, $10, locloc(@$));} -| FOR control_variable ASSIGN expression TO expression DO statement_list END_FOR - {$$ = new for_statement_c($2, $4, $6, NULL, $8, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| FOR ASSIGN expression TO expression BY expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no control variable defined in ST 'FOR' statement."); yynerrs++;} -| FOR ASSIGN expression TO expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no control variable defined in ST 'FOR' statement."); yynerrs++;} -| FOR error ASSIGN expression TO expression BY expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid control variable defined for ST 'FOR' statement."); yyerrok;} -| FOR error ASSIGN expression TO expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid control variable defined for ST 'FOR' statement."); yyerrok;} -| FOR control_variable expression TO expression BY expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':=' missing between control variable and start expression in ST 'FOR' statement."); yynerrs++;} -| FOR control_variable expression TO expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':=' missing between control variable and start expression in ST 'FOR' statement."); yynerrs++;} -| FOR control_variable error expression TO expression BY expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting ':=' between control variable and start expression in ST 'FOR' statement."); yyerrok;} -| FOR control_variable error expression TO expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting ':=' between control variable and start expression in ST 'FOR' statement."); yyerrok;} -| FOR control_variable ASSIGN TO expression BY expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no start expression defined in ST 'FOR' statement."); yynerrs++;} -| FOR control_variable ASSIGN TO expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no start expression defined in ST 'FOR' statement."); yynerrs++;} -| FOR control_variable ASSIGN error TO expression BY expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid start expression defined in ST 'FOR' statement."); yyerrok;} -| FOR control_variable ASSIGN error TO expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid start expression in ST 'FOR' statement."); yyerrok;} -| FOR control_variable ASSIGN expression error expression BY expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locf(@5), locl(@5), "expecting 'TO' between start expression and end expression in ST 'FOR' statement."); yyerrok;} -| FOR control_variable ASSIGN expression error expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locf(@5), locl(@5), "expecting 'TO' between start expression and end expression in ST 'FOR' statement."); yyerrok;} -| FOR control_variable ASSIGN expression TO expression error expression DO statement_list END_FOR - {$$ = NULL; print_err_msg(locf(@7), locl(@7), "expecting 'BY' between end expression and step expression in ST 'FOR' statement."); yyerrok;} -| FOR control_variable ASSIGN expression TO expression BY expression error statement_list END_FOR - {$$ = NULL; print_err_msg(locf(@9), locl(@9), "expecting 'DO' after step expression in ST 'FOR' statement."); yyerrok;} -| FOR control_variable ASSIGN expression TO expression error statement_list END_FOR - {$$ = NULL; print_err_msg(locf(@7), locl(@7), "expecting 'DO' after end expression in ST 'FOR' statement."); yyerrok;} -| FOR control_variable ASSIGN expression TO expression BY expression DO END_FOR - {$$ = NULL; print_err_msg(locl(@9), locf(@10), "no statement(s) defined after 'DO' in ST 'FOR' statement."); yynerrs++;} -| FOR control_variable ASSIGN expression TO expression DO END_FOR - {$$ = NULL; print_err_msg(locl(@7), locf(@8), "no statement(s) defined after 'DO' in ST 'FOR' statement."); yynerrs++;} -| FOR control_variable ASSIGN expression TO expression BY expression DO error END_FOR - {$$ = NULL; print_err_msg(locf(@10), locl(@10), "invalid statement(s) defined after 'DO' in ST 'FOR' statement."); yyerrok;} -| FOR control_variable ASSIGN expression TO expression DO error END_FOR - {$$ = NULL; print_err_msg(locf(@8), locl(@8), "invalid statement(s) defined after 'DO' in ST 'FOR' statement."); yyerrok;} -| FOR control_variable error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yyerrok;} -| FOR control_variable ASSIGN expression error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yyerrok;} -| FOR control_variable ASSIGN expression TO expression DO statement_list END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yynerrs++;} -| FOR control_variable ASSIGN expression TO expression BY expression error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yyerrok;} -| FOR control_variable ASSIGN expression TO expression BY expression DO statement_list END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yynerrs++;} -| FOR error END_FOR - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'FOR' statement."); yyerrok;} -/* ERROR_CHECK_END */ -; - -/* The spec has the syntax - * control_variable: identifier; - * but then defines the semantics of control_variable - * (Section 3.3.2.4) as being of an integer type - * (e.g., SINT, INT, or DINT). - * - * Obviously this presuposes that the control_variable - * must have been declared in some VAR .. END_VAR - * We must therefore change the syntax to read - * control_variable: prev_declared_variable_name; - * - * If we don't, then the correct use of any previosuly declared - * variable would result in an incorrect syntax error -*/ -control_variable: - prev_declared_variable_name - {$$ = new symbolic_variable_c($1,locloc(@$));}; -// control_variable: identifier {$$ = $1;}; - -/* Integrated directly into for_statement */ -/* -for_list: - expression TO expression [BY expression] -; -*/ - - -while_statement: - WHILE expression DO statement_list END_WHILE - {$$ = new while_statement_c($2, $4, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| WHILE DO statement_list END_WHILE - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'WHILE' statement."); yynerrs++;} -| WHILE error DO statement_list END_WHILE - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'WHILE' statement."); yyerrok;} -| WHILE expression error statement_list END_WHILE - {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'DO' after test expression in ST 'WHILE' statement."); yyerrok;} -| WHILE expression DO END_WHILE - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no statement(s) defined after 'DO' in ST 'WHILE' statement."); yynerrs++;} -| WHILE expression DO error END_WHILE - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid statement(s) defined after 'DO' in ST 'WHILE' statement."); yyerrok;} -| WHILE expression error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'WHILE' statement in ST."); yyerrok;} -| WHILE expression DO statement_list END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'WHILE' statement in ST."); yynerrs++;} -| WHILE error END_WHILE - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'WHILE' statement."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -repeat_statement: - REPEAT statement_list UNTIL expression END_REPEAT - {$$ = new repeat_statement_c($2, $4, locloc(@$));} -/* ERROR_CHECK_BEGIN */ -| REPEAT UNTIL expression END_REPEAT - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no statement(s) defined after 'REPEAT' in ST 'REPEAT' statement."); yynerrs++;} -| REPEAT error UNTIL expression END_REPEAT - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid statement(s) defined after 'REPEAT' for ST 'REPEAT' statement."); yyerrok;} -| REPEAT statement_list UNTIL END_REPEAT - {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no test expression defined after 'UNTIL' in ST 'REPEAT' statement.");} -| REPEAT statement_list UNTIL error END_REPEAT - {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid test expression defined after 'UNTIL' in ST 'REPEAT' statement."); yyerrok;} -| REPEAT statement_list END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'REPEAT' statement in ST."); yynerrs++;} -| REPEAT statement_list UNTIL expression error END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'REPEAT' statement in ST."); yyerrok;} -| REPEAT error END_REPEAT - {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'REPEAT' statement."); yyerrok;} -/* ERROR_CHECK_END */ -; - - -exit_statement: - EXIT {$$ = new exit_statement_c(locloc(@$));} -; - - - - - -%% - -#include /* required for printf() */ -#include -#include "../util/symtable.hh" - -/* variables defined in code generated by flex... */ -extern FILE *yyin; -extern int yylineno; -extern tracking_t* current_tracking; - - - - -/*************************************************************************************************/ -/* NOTE: These variables are really parameters we would like the stage2__ function to pass */ -/* to the yyparse() function. However, the yyparse() function is created automatically */ -/* by bison, so we cannot add parameters to this function. The only other */ -/* option is to use global variables! yuck! */ -/*************************************************************************************************/ - -/* A global flag used to tell the parser if overloaded funtions should be allowed. - * The IEC 61131-3 standard allows overloaded funtions in the standard library, - * but disallows them in user code... - * - * In essence, a parameter we would like to pass to the yyparse() function but - * have to do it using a global variable, as the yyparse() prototype is fixed by bison. - */ -bool allow_function_overloading = false; - -/* | [var1_list ','] variable_name '..' */ -/* NOTE: This is an extension to the standard!!! */ -/* In order to be able to handle extensible standard functions - * (i.e. standard functions that may have a variable number of - * input parameters, such as AND(word#33, word#44, word#55, word#66), - * we have extended the acceptable syntax to allow var_name '..' - * in an input variable declaration. - * - * This allows us to parse the declaration of standard - * extensible functions and load their interface definition - * into the abstract syntax tree just like we do to other - * user defined functions. - * This has the advantage that we can later do semantic - * checking of calls to functions (be it a standard or user defined - * function) in (almost) exactly the same way. - * - * Of course, we have a flag that disables this syntax when parsing user - * written code, so we only allow this extra syntax while parsing the - * 'header' file that declares all the standard IEC 61131-3 functions. - */ -bool allow_extensible_function_parameters = false; - -/* A global flag used to tell the parser whether to include the full variable location - * when printing out error messages... - */ -bool full_token_loc; - -/* A pointer to the root of the parsing tree that will be generated - * by bison. - */ -symbol_c *tree_root; - - - -/* The following function is called automatically by bison whenever it comes across - * an error. Unfortunately it calls this function before executing the code that handles - * the error itself, so we cannot print out the correct line numbers of the error location - * over here. - * Our solution is to store the current error message in a global variable, and have all - * error action handlers call the function print_err_msg() after setting the location - * (line number) variable correctly. - */ -const char *current_error_msg; -void yyerror (const char *error_msg) { - current_error_msg = error_msg; -/* fprintf(stderr, "error %d: %s\n", yynerrs // global variable //, error_msg); */ -/* print_include_stack(); */ -} - - -/* ERROR_CHECK_BEGIN */ -bool is_current_syntax_token() { - switch (yychar) { - case ';': - case ',': - case ')': - case ']': - case '+': - case '*': - case '-': - case '/': - case '<': - case '>': - case '=': - case '&': - case OR: - case XOR: - case AND: - case AND2: - case OPER_NE: - case OPER_LE: - case OPER_GE: - case MOD: - case OPER_EXP: - case NOT: - return true; - default: - return false; - } -} -/* ERROR_CHECK_END */ - - -void print_err_msg(int first_line, - int first_column, - const char *first_filename, - long int first_order, - int last_line, - int last_column, - const char *last_filename, - long int last_order, - const char *additional_error_msg) { - - const char *unknown_file = ""; - if (first_filename == NULL) first_filename = unknown_file; - if ( last_filename == NULL) last_filename = unknown_file; - - if (full_token_loc) { - if (first_filename == last_filename) - fprintf(stderr, "%s:%d-%d..%d-%d: error : %s\n", first_filename, first_line, first_column, last_line, last_column, additional_error_msg); - else - fprintf(stderr, "%s:%d-%d..%s:%d-%d: error : %s\n", first_filename, first_line, first_column, last_filename, last_line, last_column, additional_error_msg); - } else { - fprintf(stderr, "%s:%d: error : %s\n", first_filename, first_line, additional_error_msg); - } - //fprintf(stderr, "error %d: %s\n", yynerrs /* a global variable */, additional_error_msg); - print_include_stack(); - //fprintf(stderr, "%s(%d-%d): %s\n", current_filename, first_line, last_line, current_error_msg); -} - - - -/* If function overloading is on, we allow several functions with the same name. - * - * However, to support standard functions, we also allow functions named - * AND, MOD, NOT, OR, XOR, ADD, ... - */ -/* -identifier_c *token_2_identifier_c(char *value, ) { - identifier_c tmp = new identifier_c(value, locloc(@$)); - if (!allow_function_overloading) { - fprintf(stderr, "Function overloading not allowed. Invalid identifier %s\n", ((token_c *)($$))->value); - ERROR; - } - } -} -*/ - -/* convert between an il_operator to a function name */ -/* This a kludge! - * It is required because our language requires more than one - * look ahead token, and bison only works with one! - */ -#define op_2_str(op, str) {\ - op ## _operator_c *ptr = dynamic_cast(il_operator); \ - if (ptr != NULL) name = str; \ -} - -/* NOTE: this code is very ugly and un-eficient, but I (Mario) have many - * more things to worry about right now, so just let it be... - */ -symbol_c *il_operator_c_2_identifier_c(symbol_c *il_operator) { - const char *name = NULL; - identifier_c *res; - - op_2_str(NOT, "NOT"); - - op_2_str(AND, "AND"); - op_2_str(OR, "OR"); - op_2_str(XOR, "XOR"); - op_2_str(ADD, "ADD"); - op_2_str(SUB, "SUB"); - op_2_str(MUL, "MUL"); - op_2_str(DIV, "DIV"); - op_2_str(MOD, "MOD"); - op_2_str(GT, "GT"); - op_2_str(GE, "GE"); - op_2_str(EQ, "EQ"); - op_2_str(LT, "LT"); - op_2_str(LE, "LE"); - op_2_str(NE, "NE"); - - op_2_str(LD, "LD"); - op_2_str(LDN, "LDN"); - op_2_str(ST, "ST"); - op_2_str(STN, "STN"); - - op_2_str(S, "S"); - op_2_str(R, "R"); - op_2_str(S1, "S1"); - op_2_str(R1, "R1"); - - op_2_str(CLK, "CLK"); - op_2_str(CU, "CU"); - op_2_str(CD, "CD"); - op_2_str(PV, "PV"); - op_2_str(IN, "IN"); - op_2_str(PT, "PT"); - - op_2_str(ANDN, "ANDN"); - op_2_str(ORN, "ORN"); - op_2_str(XORN, "XORN"); - - op_2_str(ADD, "ADD"); - op_2_str(SUB, "SUB"); - op_2_str(MUL, "MUL"); - op_2_str(DIV, "DIV"); - - op_2_str(GT, "GT"); - op_2_str(GE, "GE"); - op_2_str(EQ, "EQ"); - op_2_str(LT, "LT"); - op_2_str(LE, "LE"); - op_2_str(NE, "NE"); - - op_2_str(CAL, "CAL"); - op_2_str(CALC, "CALC"); - op_2_str(CALCN, "CALCN"); - op_2_str(RET, "RET"); - op_2_str(RETC, "RETC"); - op_2_str(RETCN, "RETCN"); - op_2_str(JMP, "JMP"); - op_2_str(JMPC, "JMPC"); - op_2_str(JMPCN, "JMPCN"); - - if (name == NULL) - ERROR; - - res = new identifier_c(strdup(name), - il_operator->first_line, - il_operator->first_column, - il_operator->first_file, - il_operator->first_order, - il_operator->last_line, - il_operator->last_column, - il_operator->last_file, - il_operator->last_order - ); - free(il_operator); - return res; -} - - -#include "standard_function_names.c" - -const char *standard_function_block_names[] = { -// 2.5.2.3.1 Bistable elements -// Table 34 - Standard bistable function blocks -"SR","RS", -// 2.5.2.3.2 Edge detection -// Table 35 - Standard edge detection function blocks -"R_TRIG","F_TRIG", -// 2.5.2.3.3 Counters -// Table 36 - Standard counter function blocks -"CTU","CTU_DINT","CTU_LINT","CTU_UDINT","CTU_ULINT", -"CTD","CTD_DINT","CTD_LINT","CTD_UDINT","CTD_ULINT", -"CTUD","CTUD_DINT","CTUD_LINT","CTUD_ULINT", -// 2.5.2.3.4 Timers -// Table 37 - Standard timer function blocks -"TP","TON","TOF", -/* end of array marker! Do not remove! */ -NULL -}; - - -#define LIBFILE "ieclib.txt" -#define DEF_LIBFILENAME LIBDIRECTORY "/" LIBFILE - -extern const char *INCLUDE_DIRECTORIES[]; - - - -int stage2__(const char *filename, - const char *includedir, /* Include directory, where included files will be searched for... */ - symbol_c **tree_root_ref, - bool full_token_loc_ /* error messages specify full token location */ - ) { - - FILE *in_file = NULL, *lib_file = NULL; - char *libfilename = NULL; - - if((in_file = fopen(filename, "r")) == NULL) { - char *errmsg = strdup2("Error opening main file ", filename); - perror(errmsg); - free(errmsg); - return -1; - } - - if (includedir != NULL) { - INCLUDE_DIRECTORIES[0] = includedir; - } - if ((libfilename = strdup3(INCLUDE_DIRECTORIES[0], "/", LIBFILE)) == NULL) { - fprintf (stderr, "Out of memory. Bailing out!\n"); - return -1; - } - - if((lib_file = fopen(libfilename, "r")) == NULL) { - char *errmsg = strdup2("Error opening library file ", libfilename); - perror(errmsg); - free(errmsg); - } - - if (lib_file == NULL) { - /* we give up... */ - free(libfilename); - fclose(in_file); - return -1; - } - - /* first parse the standard library file... */ - /* - #if YYDEBUG - yydebug = 1; - #endif - */ - yyin = lib_file; - allow_function_overloading = true; - allow_extensible_function_parameters = true; - full_token_loc = full_token_loc_; - current_filename = libfilename; - current_tracking = GetNewTracking(yyin); - if (yyparse() != 0) - ERROR; - - if (yynerrs > 0) { - fprintf (stderr, "\nFound %d error(s) in %s. Bailing out!\n", yynerrs /* global variable */, libfilename); - ERROR; - } - free(libfilename); - fclose(lib_file); - - /* if by any chance the library is not complete, we - * now add the missing reserved keywords to the list!!! - */ - for(int i = 0; standard_function_block_names[i] != NULL; i++) - if (library_element_symtable.find_value(standard_function_block_names[i]) == - library_element_symtable.end_value()) - library_element_symtable.insert(standard_function_block_names[i], standard_function_block_name_token); - - - /* now parse the input file... */ - #if YYDEBUG - yydebug = 1; - #endif - yyin = in_file; - allow_function_overloading = false; - allow_extensible_function_parameters = false; - full_token_loc = full_token_loc_; - current_filename = filename; - current_tracking = GetNewTracking(yyin); - {int res; - if ((res = yyparse()) != 0) { - fprintf (stderr, "\nParsing failed because of too many consecutive syntax errors. Bailing out!\n"); - exit(EXIT_FAILURE); - } - } - - if (yynerrs > 0) { - fprintf (stderr, "\nFound %d error(s). Bailing out!\n", yynerrs /* global variable */); - exit(EXIT_FAILURE); - } - - if (tree_root_ref != NULL) - *tree_root_ref = tree_root; - - fclose(in_file); - return 0; -} - - - diff -r 17bffb57a8c5 -r 0f24db96b519 stage1_2/iec_bison.yy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage1_2/iec_bison.yy Fri Aug 19 17:33:57 2011 +0100 @@ -0,0 +1,8307 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant + * + * 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 . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +/* + * An IEC 61131-3 compiler. + * + * Based on the + * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) + * + */ + +/* + * Stage 2 + * ======= + * + * This file contains the syntax definition of the textual + * languages IL and ST, as well as the textual version of SFC. + * The syntax parser, comprising the 2nd stage of the overall + * compiler, is generated by runing bison on this file. + */ + + + + +/**********************************************************************/ +/**********************************************************************/ +/**********************************************************************/ +/**********************************************************************/ +/******* *******/ +/******* The following syntax does not have any conflicts. *******/ +/******* *******/ +/******* P L E A S E K E E P I T T H A T W A Y ! *******/ +/******* =================================================== *******/ +/******* *******/ +/**********************************************************************/ +/**********************************************************************/ +/**********************************************************************/ +/**********************************************************************/ + + + + +%{ +#include /* required for strdup() */ + + +/* declare the token parser generated by flex... */ +int yylex(void); + +/* declare the error handler defined at the end of this file */ +void yyerror (const char *error_msg); + +/* produce a more verbose parsing error message */ +#define YYERROR_VERBOSE + +/* Include debuging code. + * Printing of debug info must then be activated by setting + * the variable yydebug to 1. + */ +#define YYDEBUG 0 + + +/* file with declaration of absyntax classes... */ +#include "../absyntax/absyntax.hh" + +/* file with declaration of token constants. Generated by bison! */ +#include "iec_bison.h" + +/* The interface through which bison and flex interact. */ +#include "stage1_2_priv.hh" + + +#include "../absyntax_utils/add_en_eno_param_decl.hh" /* required for add_en_eno_param_decl_c */ + +/* an ugly hack!! + * We will probably not need it when we decide + * to cut down the abstract syntax down to size. + * We keep it as it is until we get to write + * stages 3 and 4 of the compiler. Who knows, + * we might just find out that we really do need + * the abstract syntax tree to stay as it is + * afterall! + */ +/* for each element in list_c * + * execute the code + */ +#define FOR_EACH_ELEMENT(elem, list, code) { \ + symbol_c *elem; \ + for(int i = 0; i < list->n; i++) { \ + elem = list->elements[i]; \ + code; \ + } \ +} + + + +/* Macros used to pass the line and column locations when + * creating a new object for the abstract syntax tree. + */ +#define locloc(foo) foo.first_line, foo.first_column, foo.first_file, foo.first_order, foo.last_line, foo.last_column, foo.last_file, foo.last_order +#define locf(foo) foo.first_line, foo.first_column, foo.first_file, foo.first_order +#define locl(foo) foo.last_line, foo.last_column, foo.last_file, foo.last_order + +/* Redefine the default action to take for each rule, so that the filenames are correctly processed... */ +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \ + (Current).first_file = YYRHSLOC(Rhs, 1).first_file; \ + (Current).first_order = YYRHSLOC(Rhs, 1).first_order; \ + (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC(Rhs, N).last_column; \ + (Current).last_file = YYRHSLOC(Rhs, 1).last_file; \ + (Current).last_order = YYRHSLOC(Rhs, 1).last_order; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC(Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC(Rhs, 0).last_column; \ + (Current).first_file = (Current).last_file = \ + YYRHSLOC(Rhs, 0).last_file; \ + (Current).first_order = (Current).last_order = \ + YYRHSLOC(Rhs, 0).last_order; \ + } \ + while (0) + + +/* A macro for printing out internal parser errors... */ +#define ERROR error_exit(__FILE__,__LINE__) +/* function defined in main.cc */ +extern void error_exit(const char *file_name, int line_no); + + + +/*************************/ +/* global variables... */ +/*************************/ +/* NOTE: For some strange reason bison ver 2.3 is including these declarations + * in the iec_bison.h file, which is in turn included by flex. + * We cannot therefore define any variables over here, but merely declare + * their existance (otherwise we get errors when linking the code, since we + * would get a new variable defined each time iec_bison.h is included!). + * Even though the variables are declared 'extern' over here, they will in + * fact be defined towards the end of this same file (i.e. in the prologue) + */ + + +/* NOTE: These variable are really parameters we would like the stage2__ function to pass + * to the yyparse() function. However, the yyparse() function is created automatically + * by bison, so we cannot add parameters to this function. The only other + * option is to use global variables! yuck! + */ + +/* A global flag used to tell the parser if overloaded funtions should be allowed. + * The IEC 61131-3 standard allows overloaded funtions in the standard library, + * but disallows them in user code... + */ +extern bool allow_function_overloading; + +/* A flag to tell the compiler whether to allow the declaration + * of extensible function (i.e. functions that may have a variable number of + * input parameters, such as AND(word#33, word#44, word#55, word#66). + * This is an extension to the standard syntax. + * See comments below for details why we support this! + */ +extern bool allow_extensible_function_parameters; + +/* A global flag used to tell the parser whether to include the full variable location + * when printing out error messages... + */ +extern bool full_token_loc; + +/* A pointer to the root of the parsing tree that will be generated + * by bison. + */ +extern symbol_c *tree_root; + + + +/************************/ +/* forward declarations */ +/************************/ +/* The functions declared here are defined at the end of this file... */ + +/* Convert an il_operator_c into an identifier_c */ +symbol_c *il_operator_c_2_identifier_c(symbol_c *il_operator); + +/* return if current token is a syntax element */ +/* ERROR_CHECK_BEGIN */ +bool is_current_syntax_token(); +/* ERROR_CHECK_END */ + +/* print an error message */ +void print_err_msg(int first_line, + int first_column, + const char *first_filename, + long int first_order, + int last_line, + int last_column, + const char *last_filename, + long int last_order, + const char *additional_error_msg); +%} + + + + +// %glr-parser +// %expect-rr 1 + + +/* The following definitions need to be inside a '%code requires' + * so that they are also included in the header files. If this were not the case, + * YYLTYPE would be delcared as something in the iec.cc file, and another thing + * (actually the default value of YYLTYPE) in the iec_bison.h heder file. + */ +%code requires { +/* define a new data type to store the locations, so we can also store + * the filename in which the token is expressed. + */ +/* NOTE: since this code will be placed in the iec_bison.h header file, + * as well as the iec.cc file that also includes the iec_bison.h header file, + * declaring the typedef struct yyltype__local here would result in a + * compilation error when compiling iec.cc, as this struct would be + * declared twice. + * We therefore use the #if !defined YYLTYPE ... + * to make sure only the first declaration is parsed by the C++ compiler. + * + * At first glance it seems that what we really should do is delcare the + * YYLTYPE directly as an anonymous struct, thus: + * #define YYLTYPE struct{ ...} + * however, this also results in compilation errors. + * + * I (Mario) think this is kind of a hack. If you know how to + * do this re-declaration of YYLTYPE properly, please let me know! + */ +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED + typedef struct { + int first_line; + int first_column; + const char *first_file; + long int first_order; + int last_line; + int last_column; + const char *last_file; + long int last_order; + } yyltype__local; + #define YYLTYPE yyltype__local +#endif +} + + + +%union { + symbol_c *leaf; + list_c *list; + char *ID; /* token value */ +} + +/* + TODO: DO we need to define a destructor do free + memory when recovering from errors, or do the + class destructors already handle this? + Following is example on how to define + detructors, using the syntax: + %destructor { CODE } SYMBOLS +%union + { + char *string; + } + %token STRING + %type string + %destructor { free ($$); } STRING string +*/ + + + + +/*************************************/ +/* Prelimenary helpful constructs... */ +/*************************************/ +/* A token used to identify the very end of the input file + * after all includes have already been processed. + * + * Flex automatically returns the token with value 0 + * at the end of the file. We therefore specify here + * a token with that exact same value here, so we can use it + * to detect the very end of the input files. + */ +%token END_OF_INPUT 0 + +/* A bogus token that, in principle, flex MUST NEVER generate */ +/* USE 1: + * ====== + * This token is currently also being used as the default + * initialisation value of the token_id member in + * the symbol_c base class. + * + * USE 2 + * ===== + * This token may also be used in the future to remove + * mysterious reduce/reduce conflicts due to the fact + * that our grammar may not be LALR(1) but merely LR(1). + * This means that bison cannot handle it without some + * caoxing from ourselves. We will then need this token + * to do the coaxing... + */ +%token BOGUS_TOKEN_ID + +%type start + +%type any_identifier + +%token prev_declared_variable_name_token +%token prev_declared_direct_variable_token +%token prev_declared_fb_name_token +%type prev_declared_variable_name +%type prev_declared_direct_variable +%type prev_declared_fb_name + +%token prev_declared_simple_type_name_token +%token prev_declared_subrange_type_name_token +%token prev_declared_enumerated_type_name_token +%token prev_declared_array_type_name_token +%token prev_declared_structure_type_name_token +%token prev_declared_string_type_name_token + +%type prev_declared_simple_type_name +%type prev_declared_subrange_type_name +%type prev_declared_enumerated_type_name +%type prev_declared_array_type_name +%type prev_declared_structure_type_name +%type prev_declared_string_type_name + +%token prev_declared_derived_function_name_token +%token prev_declared_derived_function_block_name_token +%token prev_declared_program_type_name_token +%type prev_declared_derived_function_name +%type prev_declared_derived_function_block_name +%type prev_declared_program_type_name + + + + +/**********************************************************************************/ +/* B XXX - Things that are missing from the standard, but should have been there! */ +/**********************************************************************************/ + +/* Pragmas that our compiler will accept. + * See the comment in iec.flex for why these pragmas exist. + */ +%token disable_code_generation_pragma_token +%token enable_code_generation_pragma_token +%type disable_code_generation_pragma +%type enable_code_generation_pragma + + +/* All other pragmas that we do not support... */ +/* In most stage 4, the text inside the pragmas will simply be copied to the output file. + * This allows us to insert C code (if using stage 4 generating C code) + * inside/interningled with the IEC 61131-3 code! + */ +%token pragma_token +%type pragma + +/* The joining of all previous pragmas, i.e. any possible pragma */ +%type any_pragma + + +/* Where do these tokens belong?? They are missing from the standard! */ +/* NOTE: There are other tokens related to these 'EN' ENO', that are also + * missing from the standard. However, their location in the annex B is + * relatively obvious, so they have been inserted in what seems to us their + * correct place in order to ease understanding of the parser... + * + * please read the comment above the definition of 'variable' in section B1.4 for details. + */ +%token EN +%token ENO +%type en_identifier +%type eno_identifier + + + + +/***************************/ +/* B 0 - Programming Model */ +/***************************/ +%type library +%type library_element_declaration + + +/*******************************************/ +/* B 1.1 - Letters, digits and identifiers */ +/*******************************************/ +/* Done totally within flex... + letter + digit + octal_digit + hex_digit +*/ +%token identifier_token +%type identifier + +/*********************/ +/* B 1.2 - Constants */ +/*********************/ +%type constant +%type non_negative_constant + +/******************************/ +/* B 1.2.1 - Numeric Literals */ +/******************************/ +/* Done totally within flex... + bit +*/ +%type numeric_literal +%type integer_literal +%type signed_integer +%token integer_token +%type integer +%token binary_integer_token +%type binary_integer +%token octal_integer_token +%type octal_integer +%token hex_integer_token +%type hex_integer +%token real_token +%type real +%type signed_real +%type real_literal +// %type exponent +%type bit_string_literal +%type boolean_literal + +%token safeboolean_true_literal_token +%token safeboolean_false_literal_token +%token boolean_true_literal_token +%token boolean_false_literal_token + +%token FALSE +%token TRUE + + +/*******************************/ +/* B 1.2.2 - Character Strings */ +/*******************************/ +%token single_byte_character_string_token +%token double_byte_character_string_token + +%type character_string +%type single_byte_character_string +%type double_byte_character_string + + +/***************************/ +/* B 1.2.3 - Time Literals */ +/***************************/ +%type time_literal + + +/************************/ +/* B 1.2.3.1 - Duration */ +/************************/ +%type duration +%type interval +%type days +%type fixed_point +%type hours +%type minutes +%type seconds +%type milliseconds + +%type integer_d +%type integer_h +%type integer_m +%type integer_s +%type integer_ms +%type fixed_point_d +%type fixed_point_h +%type fixed_point_m +%type fixed_point_s +%type fixed_point_ms + +%token fixed_point_token +%token fixed_point_d_token +%token integer_d_token +%token fixed_point_h_token +%token integer_h_token +%token fixed_point_m_token +%token integer_m_token +%token fixed_point_s_token +%token integer_s_token +%token fixed_point_ms_token +%token integer_ms_token + +// %token TIME +%token T_SHARP + + +/************************************/ +/* B 1.2.3.2 - Time of day and Date */ +/************************************/ +%type time_of_day +%type daytime +%type day_hour +%type day_minute +%type day_second +%type date +%type date_literal +%type year +%type month +%type day +%type date_and_time + +// %token TIME_OF_DAY +// %token DATE +%token D_SHARP +// %token DATE_AND_TIME + + +/**********************/ +/* B 1.3 - Data Types */ +/**********************/ +/* Strangely, the following symbol does seem to be required! */ +// %type data_type_name +%type non_generic_type_name + + +/***********************************/ +/* B 1.3.1 - Elementary Data Types */ +/***********************************/ +/* NOTES: + * + * - To make the definition of bit_string_literal more + * concise, it is useful to use an extra non-terminal + * symbol (i.e. a grouping or construct) that groups the + * following elements (BYTE, WORD, DWORD, LWORD). + * Note that the definition of bit_string_type_name + * (according to the spec) includes the above elements + * and an extra BOOL. + * We could use an extra construct with the first four + * elements to be used solely in the definition of + * bit_string_literal, but with the objective of not + * having to replicate the actions (if we ever need + * to change them, they would need to be changed in both + * bit_string_type_name and the extra grouping), we + * have re-defined bit_string_type_name as only including + * the first four elements. + * In order to have our parser implement the specification + * correctly we have augmented every occurence of + * bit_string_type_name in other rules with the BOOL + * token. Since bit_string_type_name only appears in + * the rule for elementary_type_name, this does not + * seem to be a big concession to make! + * + * - We have added a helper symbol to concentrate the + * instantiation of STRING and WSTRING into a single + * location (elementary_string_type_name). + * These two elements show up in several other rules, + * but we want to create the equivalent abstract syntax + * in a single location of this file, in order to make + * possible future changes easier to edit... + */ +%type elementary_type_name +%type numeric_type_name +%type integer_type_name +%type signed_integer_type_name +%type unsigned_integer_type_name +%type real_type_name +%type date_type_name +%type bit_string_type_name +/* helper symbol to concentrate the instantiation + * of STRING and WSTRING into a single location + */ +%type elementary_string_type_name + +%token BYTE +%token WORD +%token DWORD +%token LWORD + +%token LREAL +%token REAL + +%token SINT +%token INT +%token DINT +%token LINT + +%token USINT +%token UINT +%token UDINT +%token ULINT + +%token WSTRING +%token STRING +%token BOOL + +%token TIME +%token DATE +%token DATE_AND_TIME +%token DT +%token TIME_OF_DAY +%token TOD + +/******************************************************/ +/* Symbols defined in */ +/* "Safety Software Technical Specification, */ +/* Part 1: Concepts and Function Blocks, */ +/* Version 1.0 – Official Release" */ +/* by PLCopen - Technical Committee 5 - 2006-01-31 */ +/******************************************************/ + +%token SAFEBYTE +%token SAFEWORD +%token SAFEDWORD +%token SAFELWORD + +%token SAFELREAL +%token SAFEREAL + +%token SAFESINT +%token SAFEINT +%token SAFEDINT +%token SAFELINT + +%token SAFEUSINT +%token SAFEUINT +%token SAFEUDINT +%token SAFEULINT + +%token SAFEWSTRING +%token SAFESTRING +%token SAFEBOOL + +%token SAFETIME +%token SAFEDATE +%token SAFEDATE_AND_TIME +%token SAFEDT +%token SAFETIME_OF_DAY +%token SAFETOD + +/********************************/ +/* B 1.3.2 - Generic data types */ +/********************************/ +/* Strangely, the following symbol does seem to be required! */ +// %type generic_type_name + +/* The following tokens do not seem to be used either + * but we declare them so they become reserved words... + */ +%token ANY +%token ANY_DERIVED +%token ANY_ELEMENTARY +%token ANY_MAGNITUDE +%token ANY_NUM +%token ANY_REAL +%token ANY_INT +%token ANY_BIT +%token ANY_STRING +%token ANY_DATE + + +/********************************/ +/* B 1.3.3 - Derived data types */ +/********************************/ +%type derived_type_name +%type single_element_type_name +// %type simple_type_name +// %type subrange_type_name +// %type enumerated_type_name +// %type array_type_name +// %type structure_type_name + +%type data_type_declaration +/* helper symbol for data_type_declaration */ +%type type_declaration_list +%type type_declaration +%type single_element_type_declaration + +%type simple_type_declaration +%type simple_spec_init +%type simple_specification + +%type subrange_type_declaration +%type subrange_spec_init +%type subrange_specification +%type subrange + +%type enumerated_type_declaration +%type enumerated_spec_init +%type enumerated_specification +/* helper symbol for enumerated_value */ +%type enumerated_value_list +%type enumerated_value +//%type enumerated_value_without_identifier + +%type array_type_declaration +%type array_spec_init +%type array_specification +/* helper symbol for array_specification */ +%type array_subrange_list +%type array_initialization +/* helper symbol for array_initialization */ +%type array_initial_elements_list +%type array_initial_elements +%type array_initial_element + +%type structure_type_declaration +%type structure_specification +%type initialized_structure +%type structure_declaration +/* helper symbol for structure_declaration */ +%type structure_element_declaration_list +%type structure_element_declaration +%type structure_element_name +%type structure_initialization +/* helper symbol for structure_initialization */ +%type structure_element_initialization_list +%type structure_element_initialization + +//%type string_type_name +%type string_type_declaration +/* helper symbol for string_type_declaration */ +%type string_type_declaration_size +/* helper symbol for string_type_declaration */ +%type string_type_declaration_init + +%token ASSIGN +%token DOTDOT /* ".." */ +%token TYPE +%token END_TYPE +%token ARRAY +%token OF +%token STRUCT +%token END_STRUCT + + + +/*********************/ +/* B 1.4 - Variables */ +/*********************/ +%type variable +%type symbolic_variable +/* helper symbol for prog_cnxn */ +%type any_symbolic_variable +%type variable_name + + + + +/********************************************/ +/* B.1.4.1 Directly Represented Variables */ +/********************************************/ +/* Done totally within flex... + location_prefix + size_prefix +*/ +%token direct_variable_token +//%type direct_variable + + +/*************************************/ +/* B.1.4.2 Multi-element Variables */ +/*************************************/ +%type multi_element_variable +/* helper symbol for any_symbolic_variable */ +%type any_multi_element_variable +%type array_variable +/* helper symbol for any_symbolic_variable */ +%type any_array_variable +%type subscripted_variable +/* helper symbol for any_symbolic_variable */ +%type any_subscripted_variable +%type subscript_list +%type subscript +%type structured_variable +/* helper symbol for any_symbolic_variable */ +%type any_structured_variable +%type record_variable +/* helper symbol for any_symbolic_variable */ +%type any_record_variable +%type field_selector + + +/******************************************/ +/* B 1.4.3 - Declaration & Initialisation */ +/******************************************/ +%type input_declarations +/* helper symbol for input_declarations */ +%type input_declaration_list +%type input_declaration +%type edge_declaration +/* en_param_declaration is not in the standard, but should be! */ +%type en_param_declaration +%type var_init_decl +%type var1_init_decl +%type var1_list +%type array_var_init_decl +%type structured_var_init_decl +%type fb_name_decl +/* helper symbol for fb_name_decl */ +%type fb_name_list_with_colon +/* helper symbol for fb_name_list_with_colon */ +%type var1_list_with_colon +// %type fb_name_list +// %type fb_name +%type output_declarations +%type var_output_init_decl +%type var_output_init_decl_list +/* eno_param_declaration is not in the standard, but should be! */ +%type eno_param_declaration +%type input_output_declarations +/* helper symbol for input_output_declarations */ +%type var_declaration_list +%type var_declaration +%type temp_var_decl +%type var1_declaration +%type array_var_declaration +%type structured_var_declaration +%type var_declarations +%type retentive_var_declarations +%type located_var_declarations +/* helper symbol for located_var_declarations */ +%type located_var_decl_list +%type located_var_decl +%type external_var_declarations +/* helper symbol for external_var_declarations */ +%type external_declaration_list +%type external_declaration +%type global_var_name +%type global_var_declarations +/* helper symbol for global_var_declarations */ +%type global_var_decl_list +%type global_var_decl +%type global_var_spec +%type located_var_spec_init +%type location +%type global_var_list +%type string_var_declaration +%type single_byte_string_var_declaration +%type single_byte_string_spec +%type double_byte_string_var_declaration +%type double_byte_string_spec +%type incompl_located_var_declarations +/* helper symbol for incompl_located_var_declarations */ +%type incompl_located_var_decl_list +%type incompl_located_var_decl +%type incompl_location +%type var_spec +/* helper symbol for var_spec */ +%type string_spec +/* intermediate helper symbol for: + * - non_retentive_var_decls + * - var_declarations + */ +%type var_init_decl_list + +%token incompl_location_token + +%token VAR_INPUT +%token VAR_OUTPUT +%token VAR_IN_OUT +%token VAR_EXTERNAL +%token VAR_GLOBAL +%token END_VAR +%token RETAIN +%token NON_RETAIN +%token R_EDGE +%token F_EDGE +%token AT + + +/***********************/ +/* B 1.5.1 - Functions */ +/***********************/ +// %type function_name +/* helper symbol for IL language */ +%type function_name_no_clashes +%type function_name_simpleop_clashes +//%type function_name_expression_clashes +/* helper symbols for ST language */ +//%type function_name_NOT_clashes +%type function_name_no_NOT_clashes + +//%type standard_function_name +/* helper symbols for IL language */ +%type standard_function_name_no_clashes +%type standard_function_name_simpleop_clashes +%type standard_function_name_expression_clashes +/* helper symbols for ST language */ +%type standard_function_name_NOT_clashes +%type standard_function_name_no_NOT_clashes + +%type derived_function_name +%type function_declaration +/* helper symbol for function_declaration */ +%type function_name_declaration +%type io_var_declarations +%type function_var_decls +%type function_body +%type var2_init_decl +/* intermediate helper symbol for function_declaration */ +%type io_OR_function_var_declarations_list +/* intermediate helper symbol for function_var_decls */ +%type var2_init_decl_list + +%token standard_function_name_token + +%token FUNCTION +%token END_FUNCTION +%token CONSTANT + + +/*****************************/ +/* B 1.5.2 - Function Blocks */ +/*****************************/ +%type function_block_type_name +%type standard_function_block_name +%type derived_function_block_name +%type function_block_declaration +%type other_var_declarations +%type temp_var_decls +%type non_retentive_var_decls +%type function_block_body +/* intermediate helper symbol for function_declaration */ +%type io_OR_other_var_declarations_list +/* intermediate helper symbol for temp_var_decls */ +%type temp_var_decls_list + +%token standard_function_block_name_token + +%token FUNCTION_BLOCK +%token END_FUNCTION_BLOCK +%token VAR_TEMP +// %token END_VAR +%token VAR +// %token NON_RETAIN +// %token END_VAR + + +/**********************/ +/* B 1.5.3 - Programs */ +/**********************/ +%type program_type_name +%type program_declaration +/* helper symbol for program_declaration */ +%type program_var_declarations_list + +%token PROGRAM +%token END_PROGRAM + + +/********************************************/ +/* B 1.6 Sequential Function Chart elements */ +/********************************************/ + +%type sequential_function_chart +%type sfc_network +%type initial_step +%type step +%type action_association_list +%type step_name +%type action_association +/* helper symbol for action_association */ +%type indicator_name_list +%type action_name +%type action_qualifier +%type qualifier +%type timed_qualifier +%type action_time +%type indicator_name +%type transition +%type steps +%type step_name_list +%type transition_priority +%type transition_condition +%type action +%type action_body +%type transition_name + + +// %token ASSIGN +%token ACTION +%token END_ACTION + +%token TRANSITION +%token END_TRANSITION +%token FROM +%token TO +%token PRIORITY + +%token INITIAL_STEP +%token STEP +%token END_STEP + +%token L +%token D +%token SD +%token DS +%token SL + +%token N +%token P +/* NOTE: the following two clash with the R and S IL operators. + * It will have to be handled when we include parsing of SFC... + */ +/* +%token R +%token S +*/ + + +/********************************/ +/* B 1.7 Configuration elements */ +/********************************/ +%type configuration_name +%type resource_type_name +%type configuration_declaration +// helper symbol for +// - configuration_declaration +// - resource_declaration +// +%type optional_global_var_declarations +// helper symbol for configuration_declaration +%type optional_access_declarations +// helper symbol for configuration_declaration +%type optional_instance_specific_initializations +// helper symbol for configuration_declaration +%type resource_declaration_list +%type resource_declaration +%type single_resource_declaration +// helper symbol for single_resource_declaration +%type task_configuration_list +// helper symbol for single_resource_declaration +%type program_configuration_list +%type resource_name +// %type access_declarations +// helper symbol for access_declarations +// %type access_declaration_list +// %type access_declaration +// %type access_path +// helper symbol for access_path +%type any_fb_name_list +%type global_var_reference +// %type access_name +%type program_output_reference +%type program_name +// %type direction +%type task_configuration +%type task_name +%type task_initialization +// 3 helper symbols for task_initialization +%type task_initialization_single +%type task_initialization_interval +%type task_initialization_priority + +%type data_source +%type program_configuration +// helper symbol for program_configuration +%type optional_task_name +// helper symbol for program_configuration +%type optional_prog_conf_elements +%type prog_conf_elements +%type prog_conf_element +%type fb_task +%type prog_cnxn +%type prog_data_source +%type data_sink +%type instance_specific_initializations +// helper symbol for instance_specific_initializations +%type instance_specific_init_list +%type instance_specific_init +// helper symbol for instance_specific_init +%type fb_initialization + +%type prev_declared_global_var_name +%token prev_declared_global_var_name_token + +%type prev_declared_program_name +%token prev_declared_program_name_token + +%type prev_declared_resource_name +%token prev_declared_resource_name_token + +%token prev_declared_configuration_name_token + +// %type prev_declared_task_name +// %token prev_declared_task_name_token + +%token CONFIGURATION +%token END_CONFIGURATION +%token TASK +%token RESOURCE +%token ON +%token END_RESOURCE +%token VAR_CONFIG +%token VAR_ACCESS +// %token END_VAR +%token WITH +// %token PROGRAM +// %token RETAIN +// %token NON_RETAIN +// %token PRIORITY +%token SINGLE +%token INTERVAL +%token READ_WRITE +%token READ_ONLY + + +/***********************************/ +/* B 2.1 Instructions and Operands */ +/***********************************/ +%type instruction_list +%type il_instruction +%type il_incomplete_instruction +%type label +%type il_simple_operation +// helper symbol for il_simple_operation +//%type il_simple_operator_clash_il_operand +%type il_expression +%type il_jump_operation +%type il_fb_call +%type il_formal_funct_call +// helper symbol for il_formal_funct_call +%type il_expr_operator_clash_eol_list +%type il_operand +%type il_operand_list +// helper symbol for il_simple_operation +%type il_operand_list2 +%type simple_instr_list +%type il_simple_instruction +%type il_param_list +%type il_param_instruction_list +%type il_param_instruction +%type il_param_last_instruction +%type il_param_assignment +%type il_param_out_assignment + +%token EOL + + +/*******************/ +/* B 2.2 Operators */ +/*******************/ +%token sendto_identifier_token +%type sendto_identifier + +%type LD_operator +%type LDN_operator +%type ST_operator +%type STN_operator +%type NOT_operator +%type S_operator +%type R_operator +%type S1_operator +%type R1_operator +%type CLK_operator +%type CU_operator +%type CD_operator +%type PV_operator +%type IN_operator +%type PT_operator +%type AND_operator +%type AND2_operator +%type OR_operator +%type XOR_operator +%type ANDN_operator +%type ANDN2_operator +%type ORN_operator +%type XORN_operator +%type ADD_operator +%type SUB_operator +%type MUL_operator +%type DIV_operator +%type MOD_operator +%type GT_operator +%type GE_operator +%type EQ_operator +%type LT_operator +%type LE_operator +%type NE_operator +%type CAL_operator +%type CALC_operator +%type CALCN_operator +%type RET_operator +%type RETC_operator +%type RETCN_operator +%type JMP_operator +%type JMPC_operator +%type JMPCN_operator + +%type il_simple_operator +%type il_simple_operator_clash +%type il_simple_operator_clash1 +%type il_simple_operator_clash2 +%type il_simple_operator_noclash + +//%type il_expr_operator +%type il_expr_operator_clash +%type il_expr_operator_noclash + +%type il_assign_operator +%type il_assign_out_operator +%type il_call_operator +%type il_return_operator +%type il_jump_operator + + +%token LD +%token LDN +%token ST +%token STN +%token NOT +%token S +%token R +%token S1 +%token R1 +%token CLK +%token CU +%token CD +%token PV +%token IN +%token PT +%token AND +%token AND2 /* character '&' in the source code*/ +%token OR +%token XOR +%token ANDN +%token ANDN2 /* characters '&N' in the source code */ +%token ORN +%token XORN +%token ADD +%token SUB +%token MUL +%token DIV +%token MOD +%token GT +%token GE +%token EQ +%token LT +%token LE +%token NE +%token CAL +%token CALC +%token CALCN +%token RET +%token RETC +%token RETCN +%token JMP +%token JMPC +%token JMPCN + +%token SENDTO /* "=>" */ + + +/***********************/ +/* B 3.1 - Expressions */ +/***********************/ +/* NOTE: + * + * - unary_operator, multiply_operator, + * add_operator and comparison_operator + * are not required. Their values are integrated + * directly into other rules... + */ +%type expression +%type xor_expression +%type and_expression +%type comparison +%type equ_expression +// %type comparison_operator +%type add_expression +// %type add_operator +%type term +// %type multiply_operator +%type power_expression +%type unary_expression +// %type unary_operator +%type primary_expression +%type non_negative_primary_expression +/* intermediate helper symbol for primary_expression */ +%type function_invocation + +// %token AND +// %token XOR +// %token OR +// %token MOD +// %token NOT +%token OPER_NE +%token OPER_GE +%token OPER_LE +%token OPER_EXP + + +/********************/ +/* B 3.2 Statements */ +/********************/ +%type statement_list +%type statement + + + +/*********************************/ +/* B 3.2.1 Assignment Statements */ +/*********************************/ +%type assignment_statement +// %token ASSIGN /* ":=" */ + + +/*****************************************/ +/* B 3.2.2 Subprogram Control Statements */ +/*****************************************/ +%type subprogram_control_statement +%type return_statement +%type fb_invocation +// %type param_assignment +%type param_assignment_formal +%type param_assignment_nonformal +/* helper symbols for fb_invocation */ +%type param_assignment_formal_list +%type param_assignment_nonformal_list + +// %token ASSIGN +// %token SENDTO /* "=>" */ +%token RETURN + + +/********************************/ +/* B 3.2.3 Selection Statements */ +/********************************/ +%type selection_statement +%type if_statement +%type case_statement +%type case_element +%type case_list +%type case_list_element +/* helper symbol for if_statement */ +%type elseif_statement_list +/* helper symbol for elseif_statement_list */ +%type elseif_statement +/* helper symbol for case_statement */ +%type case_element_list + +%token IF +%token THEN +%token ELSIF +%token ELSE +%token END_IF + +%token CASE +// %token OF +// %token ELSE +%token END_CASE + + + +/********************************/ +/* B 3.2.4 Iteration Statements */ +/********************************/ +%type iteration_statement +%type for_statement +%type control_variable +%type while_statement +%type repeat_statement +%type exit_statement +/* Integrated directly into for_statement */ +// %type for_list + +%token FOR +// %token ASSIGN +// %token TO +%token BY +%token DO +%token END_FOR + +%token WHILE +// %token DO +%token END_WHILE + +%token REPEAT +%token UNTIL +%token END_REPEAT + +%token EXIT + + +%% + + + + +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ + + +start: + library {$$ = $1;} +; + + +/**********************************************************************************/ +/* B XXX - Things that are missing from the standard, but should have been there! */ +/**********************************************************************************/ + + +/* the pragmas... */ + + +disable_code_generation_pragma: + disable_code_generation_pragma_token {$$ = new disable_code_generation_pragma_c(locloc(@$));} + +enable_code_generation_pragma: + enable_code_generation_pragma_token {$$ = new enable_code_generation_pragma_c(locloc(@$));} + +pragma: + pragma_token {$$ = new pragma_c($1, locloc(@$));} + +any_pragma: + disable_code_generation_pragma +| enable_code_generation_pragma +| pragma +; + + +/* EN/ENO */ +/* Tese tokens are essentially used as variable names, so we handle them + * similarly to these... + */ +en_identifier: + EN {$$ = new identifier_c("EN", locloc(@$));} +; + +eno_identifier: + ENO {$$ = new identifier_c("ENO", locloc(@$));} +; + + + +/*************************************/ +/* Prelimenary helpful constructs... */ +/*************************************/ + +/* NOTE: + * short version: + * identifier is used for previously undeclared identifiers + * any_identifier is used when any identifier, previously + * declared or not, is required in the syntax. + * + * long version: + * When flex comes across an identifier, it first + * searches through the currently declared variables, + * functions, types, etc... to determine if it has + * been previously declared. + * Only if the identifier has not yet been declared + * will it return an identifier_token (later turned into + * an identifier symbol by the bison generated syntax parser). + * + * Some constructs in the syntax, such as when calling + * a function 'F(var1 := 1; var2 := 2);', will accept _any_ + * identifier in 'var1', even if it has been previously + * declared in the current scope, since var1 belongs to + * another scope (the variables declared in function F). + * + * For the above reason, we need to define the symbol + * any_identifier. All the symbols that may become an + * any_identifier are expected to be stored in the + * abstract syntax as a identifier_c + */ +/* NOTE: + * Type names, function names, function block type names and + * program type names are considerd keywords once they are defined, + * so may no longer be used for variable names! + * BUT the spec is confusing on this issue, as it is not clear when + * a function name should be considered as defined. If it is to be + * considered defined only from the location from where it is declared + * and onwards, it means that before it is declared its name may be + * used for variable names! + * This means that we must allow names previously used for functions + * (et. al.) to also constitue an any_identifier! + */ +any_identifier: + identifier +| prev_declared_fb_name +| prev_declared_variable_name +/**/ +| prev_declared_enumerated_type_name +| prev_declared_simple_type_name +| prev_declared_subrange_type_name +| prev_declared_array_type_name +| prev_declared_structure_type_name +| prev_declared_string_type_name +| prev_declared_derived_function_name +| prev_declared_derived_function_block_name +| prev_declared_program_type_name +/**/ +| prev_declared_resource_name +| prev_declared_program_name +| prev_declared_global_var_name +; + + +prev_declared_variable_name: prev_declared_variable_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_fb_name: prev_declared_fb_name_token {$$ = new identifier_c($1, locloc(@$));}; + +prev_declared_simple_type_name: prev_declared_simple_type_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_subrange_type_name: prev_declared_subrange_type_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_enumerated_type_name: prev_declared_enumerated_type_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_array_type_name: prev_declared_array_type_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_structure_type_name: prev_declared_structure_type_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_string_type_name: prev_declared_string_type_name_token {$$ = new identifier_c($1, locloc(@$));}; + +prev_declared_derived_function_name: prev_declared_derived_function_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_derived_function_block_name: prev_declared_derived_function_block_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_program_type_name: prev_declared_program_type_name_token {$$ = new identifier_c($1, locloc(@$));}; + + + +/***************************/ +/* B 0 - Programming Model */ +/***************************/ +library: + /* empty */ + {if (tree_root == NULL) + tree_root = new library_c(); + $$ = (list_c *)tree_root; + } +| library library_element_declaration + {$$ = $1; $$->add_element($2);} +| library any_pragma + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| library error library_element_declaration + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unknown syntax error."); yyerrok;} +| library error END_OF_INPUT + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unknown syntax error."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +library_element_declaration: + data_type_declaration +| function_declaration +| function_block_declaration +| program_declaration +| configuration_declaration +; + + + +/*******************************************/ +/* B 1.1 - Letters, digits and identifiers */ +/*******************************************/ +/* NOTE: the spec defines identifier as: + * identifier ::= (letter|('_' (letter|digit))) {['_'] (letter|digit)} + * In essence, any sequence of letters or digits, starting with a letter + * or '_'. + * + * On section 2.1.3 (pg 26) , the spec states + * "The keywords listed in annex C shall not be used for any other purpose, + * e.g., variable names or extensions as defined in 1.5.1." + * (NOTE: the spec itself does not follow this rule, as it defines standard + * functions with names identidal to keywords, e.g. 'MOD', 'NOT' !!. This is + * another issue altogether, and is worked around somewhere else...) + * + * This means that we must re-define indentifier so as to exclude + * any keywords defined in annex C. + * + * Note also that the list includes + * - Data type names + * - Function names + * - Function Block names + * This means that any named used for a function name, data type name + * or function block name, essentially becomes a keyword, and may therefore + * no longer be re-used for any other use! (see NOTE 2) + * + * In our case, excluding the keywords is achieved in the lexical parser, + * by two mechanisms: + * (1) giving higher priority to the keywords (tokens) than to identifiers, + * so when the lexical parser finds a keyword it will be parsed as a + * token before being parsed as an identifier. + * (2) when an identifier is found that is not a keyword, the lexical parser + * then looks in the global symbol table, and will not return an identifier + * if the name has been previously used as a data type name, function name, + * or function block name! (In these cases it will return a + * prev_declared_function_name_token, etc...). + * + * Unfortunately, the language (especially IL) uses tokens that are + * not defined as keywords in the spec (e.g. 'IN', 'R1', 'S1', 'PT', etc...)! + * This means that it is valid to name a function 'IN', a variable 'PT', etc... + * In order to solve this potential ambiguity, flex only parses the above + * identifiers as keywords / tokens if we are currently parsing IL code. + * When parsing all code other than IL code, the above identifiers are treated + * just like any other identifier. + * + * + * + * + * NOTE 2: + * I (Mario) find it strange that the writers of the spec really want + * names previously used for function names, data type names or function + * block names, to become full fledged keywords. I understand that they + * do not want these names being used as variable names, but how about + * enumeration values? How about structure element names? + * If we interpret the spec literally, these would not be accepted, + * which would probably burden the programmer quite a bit, in making sure + * all these name don't clash! + * + * + * + * NOTE 3: The keywords, as specified in Annex C are... + * + * - Data type names + * - Function names + * - Function Block names + * - ACTION...END_ACTION + * - ARRAY...OF + * - AT + * - CASE...OF...ELSE...END_CASE + * - CONFIGURATION...END_CONFIGURATION + * - CONSTANT + * - EN, ENO + * - EXIT + * - FALSE + * - F_EDGE + * - FOR...TO...BY...DO...END_FOR + * - FUNCTION...END_FUNCTION + * - FUNCTION_BLOCK...END_FUNCTION_BLOCK + * - IF...THEN...ELSIF...ELSE...END_IF + * - INITIAL_STEP...END_STEP + * - NOT, MOD, AND, XOR, OR + * - PROGRAM...WITH... + * - PROGRAM...END_PROGRAM + * - R_EDGE + * - READ_ONLY, READ_WRITE + * - REPEAT...UNTIL...END_REPEAT + * - RESOURCE...ON...END_RESOURCE + * - RETAIN, NON_RETAIN + * - RETURN + * - STEP...END_STEP + * - STRUCT...END_STRUCT + * - TASK + * - TRANSITION...FROM...TO...END_TRANSITION + * - TRUE + * - TYPE...END_TYPE + * - VAR...END_VAR + * - VAR_INPUT...END_VAR + * - VAR_OUTPUT...END_VAR + * - VAR_IN_OUT...END_VAR + * - VAR_TEMP...END_VAR + * - VAR_EXTERNAL...END_VAR + * - VAR_ACCESS...END_VAR + * - VAR_CONFIG...END_VAR + * - VAR_GLOBAL...END_VAR + * - WHILE...DO...END_WHILE + * - WITH + */ + +identifier: + identifier_token {$$ = new identifier_c($1, locloc(@$));} +; + + + +/*********************/ +/* B 1.2 - Constants */ +/*********************/ +constant: + numeric_literal +| character_string +| time_literal +| bit_string_literal +| boolean_literal +/* NOTE: in order to remove reduce/reduce conflicts, + * [between -9.5 being parsed as + * (i) a signed real, + * (ii) or as a real preceded by the '-' operator + * ] + * we need to define a variant of the constant construct + * where any constant is never preceded by the '-' character. + * In order to do this, we have borugh the signed_real + * directly into the definition of the constant construct + * (so we can define another non_negative_constant + * construct that does not include it!) + */ +| signed_real +/* NOTE: in order to remove reduce/reduce conflicts, + * unsigned_integer, signed_integer, binary_integer, octal_integer + * and hex_integer have been integrated directly into + * the constants construct, instead of belonging to + * both the bit_string_literal or integer_literal + * construct. + */ +/* NOTE: unsigned_integer, although used in some + * rules, is not defined in the spec! + * We therefore replaced unsigned_integer as integer + */ +/*| integer {} */ /* i.e. an unsigned_integer */ /* NOTE: already included as a signed integer! */ +| signed_integer +| binary_integer +| octal_integer +| hex_integer +; + + +/* NOTE: in order to remove reduce/reduce conflicts, + * [between -9.5 being parsed as + * (i) a signed real, + * (ii) or as a real preceded by the '-' operator + * ] + * we need to define a variant of the constant construct + * where any constant is never preceded by the '-' character. + * In order to do this, we have borugh the signed_real + * directly into the definition of the constant construct + * (so we can define another non_negative_constant + * construct that does not include it!) + */ +non_negative_constant: + numeric_literal +| character_string +| time_literal +| bit_string_literal +| boolean_literal +/* NOTE: in order to remove reduce/reduce conflicts, + * [between -9.5 being parsed as + * (i) a signed real, + * (ii) or as a real preceded by the '-' operator + * ] + * we need to define a variant of the constant construct + * where any constant is never preceded by the '-' character. + * In order to do this, we have borugh the signed_real + * directly into the definition of the constant construct + * (so we can define another non_negative_constant + * construct that does not include it!) + */ +/* | signed_real */ +| real /* an unsigned real */ +/* NOTE: in order to remove reduce/reduce conflicts, + * unsigned_integer, signed_integer, binary_integer, octal_integer + * and hex_integer have been integrated directly into + * the constants construct, instead of belonging to + * both the bit_string_literal or integer_literal + * construct. + */ +/* NOTE: unsigned_integer, although used in some + * rules, is not defined in the spec! + * We therefore replaced unsigned_integer as integer + */ +| integer /* i.e. an unsigned_integer */ +/* | signed_integer */ +| binary_integer +| octal_integer +| hex_integer +; + + +/******************************/ +/* B 1.2.1 - Numeric Literals */ +/******************************/ +/* NOTES: + * + * - integer is parsed by flex, but signed_integer + * is parsed by bison. Flex cannot parse a signed + * integer correctly! For example: '123+456' + * would be parsed by flex as an {integer} {signed_integer} + * instead of {integer} '+' {integer} + * + * - Neither flex nor bison can parse a real_literal + * completely (and correctly). + * Note that we cannot use the definition of real in bison as + * real: signed_integer '.' integer [exponent] + * exponent: {'E'|'e'} ['+'|'-'] integer + * because 123e45 would be parsed by flex as + * integer (123) identifier (e45). + * I.e., flex never hands over an 'e' directly to + * bison, but rather interprets it as an identifier. + * I guess we could jump through hoops and get it + * working in bison, but the following alternative + * seems more straight forward... + * + * We therefore had to break up the definition of + * real_literal in discrete parts: + * real_literal: [real_type_name '#'] singned_real + * signed_real: ['+'|'-'] real + * Flex handles real, while bison handles signed_real + * and real_literal. + * + * - According to the spec, integer '.' integer + * may be reduced to either a real or a fixed_point. + * It is nevertheless possible to figure out from the + * context which of the two rules should be used in + * the reduction. + * Unfortunately, due to the issue described above + * regarding the exponent of a real, the syntax + * integer '.' integer + * must be parsed by flex as a single token (i.e. + * fixed_point_token). This means we must add fixed_point + * to the definition of real! + * + * - The syntax also uses a construct + * fixed_point: integer ['.' integer] + * Notice that real is not defined based on fixed point, + * but rather off integer thus: + * real: integer '.' integer [exponent] + * This means that a real may not be composed of a single + * integer, unlike the construct fixed_point! + * This also means that a + * integer '.' integer + * could be reduced to either a real or a fixed_point + * construct. It is probably possible to decide by looking + * at the context, BUT: + * Unfortunatley, due to the reasons explained way above, + * a real (with an exponent) has to be handled by flex as a + * whole. This means that we cannot leave to bison (the syntax + * parser) the decision of how to reduce an + * integer '.' integer + * (either to real or to fixed_point) + * The decision on how to reduce it would need to be done by + * ther lexical analyser (i.e. flex). But flex cannot do this + * sort of thing. + * The solution I (Mario) adopted is to have flex return + * a real_token on (notice that exponent is no longer optional) + * integer '.' integer exponent + * and to return a fixed_point_token when it finds + * integer '.' integer + * We now redefine real and fixed_point to be + * fixed_point: fixed_point_token | integer + * real: real_token | fixed_point_token + */ +real: + real_token {$$ = new real_c($1, locloc(@$));} +| fixed_point_token {$$ = new real_c($1, locloc(@$));} +; + +integer: integer_token {$$ = new integer_c($1, locloc(@$));}; +binary_integer: binary_integer_token {$$ = new binary_integer_c($1, locloc(@$));}; +octal_integer: octal_integer_token {$$ = new octal_integer_c($1, locloc(@$));}; +hex_integer: hex_integer_token {$$ = new hex_integer_c($1, locloc(@$));}; + +numeric_literal: + integer_literal +| real_literal +; + + +integer_literal: + integer_type_name '#' signed_integer + {$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));} +| integer_type_name '#' binary_integer + {$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));} +| integer_type_name '#' octal_integer + {$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));} +| integer_type_name '#' hex_integer + {$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));} +/* NOTE: see note in the definition of constant for reason + * why signed_integer, binary_integer, octal_integer + * and hex_integer are missing here! + */ +/* ERROR_CHECK_BEGIN */ +| integer_type_name signed_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} +| integer_type_name binary_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} +| integer_type_name octal_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} +| integer_type_name hex_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} +| integer_type_name '#' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for integer literal.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for integer literal."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +signed_integer: + integer +| '+' integer {$$ = $2;} +| '-' integer {$$ = new neg_integer_c($2, locloc(@$));} +; + + +real_literal: +/* NOTE: see note in the definition of constant for reason + * why signed_real is missing here! + */ +/* signed_real */ + real_type_name '#' signed_real + {$$ = new real_literal_c($1, $3, locf(@1), locl(@3));} +/* ERROR_CHECK_BEGIN */ +| real_type_name signed_real + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between real type name and value in real literal."); yynerrs++;} +| real_type_name '#' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for real literal.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for real literal."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +signed_real: + real +| '+' real {$$ = $2;} +| '-' real {$$ = new neg_real_c($2, locloc(@2));} +; + + + +bit_string_literal: + bit_string_type_name '#' integer /* i.e. unsigned_integer */ + {$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));} +| bit_string_type_name '#' binary_integer + {$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));} +| bit_string_type_name '#' octal_integer + {$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));} +| bit_string_type_name '#' hex_integer + {$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));} +/* NOTE: see note in the definition of constant for reason + * why unsigned_integer, binary_integer, octal_integer + * and hex_integer are missing here! + */ +/* NOTE: see note under the B 1.2.1 section of token + * and grouping type definition for reason why the use of + * bit_string_type_name, although seemingly incorrect, is + * really correct here! + */ +/* ERROR_CHECK_BEGIN */ +| bit_string_type_name integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} +| bit_string_type_name binary_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} +| bit_string_type_name octal_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} +| bit_string_type_name hex_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} +| bit_string_type_name '#' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for bit string literal.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for bit string literal."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +boolean_literal: + boolean_true_literal_token + {$$ = new boolean_literal_c(new bool_type_name_c(locloc(@$)), + new boolean_true_c(locloc(@$)), + locloc(@$)); + } +| boolean_false_literal_token + {$$ = new boolean_literal_c(new bool_type_name_c(locloc(@$)), + new boolean_false_c(locloc(@$)), + locloc(@$)); + } +| safeboolean_true_literal_token + {$$ = new boolean_literal_c(new safebool_type_name_c(locloc(@$)), + new boolean_true_c(locloc(@$)), + locloc(@$)); + } +| safeboolean_false_literal_token + {$$ = new boolean_literal_c(new safebool_type_name_c(locloc(@$)), + new boolean_false_c(locloc(@$)), + locloc(@$)); + } +| FALSE + {$$ = new boolean_literal_c(NULL, + new boolean_false_c(locloc(@$)), + locloc(@$)); + } +| TRUE + {$$ = new boolean_literal_c(NULL, + new boolean_true_c(locloc(@$)), + locloc(@$)); + } +/* +| BOOL '#' '1' {} +| BOOL '#' '0' {} +*/ +/* NOTE: the rules + * BOOL '#' '1' + * and + * BOOL '#' '0' + * do not work as expected... + * Consider that we are using 'BOOL' and '#' as tokens + * that flex hands over to bison (yacc). Because flex would + * then parse the single '1' or '0' as an integer, + * the rule in bison would have to be + * BOOL '#' integer, followed by verifying of the + * integer has the correct value! + * + * We therefore have flex return TRUE whenever it + * comes across 'TRUE' or 'BOOL#1', and FALSE whenever + * it comes across 'FALSE' or 'BOOL#0'. + * Note that this means that flex will parse "BOOL#01" + * as FALSE followed by an integer ('1'). + * Bison should detect this as an error, so we should + * be OK. + * + * Another option would be to change the rules to accept + * BOOL '#' integer + * but then check whether the integer has a correct + * value! At the moment I feel that the first option + * is more straight forward. + */ +; + + + +/*******************************/ +/* B 1.2.2 - Character Strings */ +/*******************************/ +/* Transform the tokens given us by flex into leafs */ +single_byte_character_string: single_byte_character_string_token + {$$ = new single_byte_character_string_c($1, locloc(@$));}; + +double_byte_character_string: double_byte_character_string_token + {$$ = new double_byte_character_string_c($1, locloc(@$));}; + + +character_string: + single_byte_character_string +| double_byte_character_string +; + + + + + +/***************************/ +/* B 1.2.3 - Time Literals */ +/***************************/ +time_literal: + time_of_day +| date +| date_and_time +| duration +; + + +/************************/ +/* B 1.2.3.1 - Duration */ +/************************/ +duration: +/* (T | TIME) '#' ['-'] interval */ +/* NOTE: since TIME is also a data type, it is a keyword + * and may therefore be handled by a token. + * + * Unfortunately T is not a data type, and therefore + * not a keyword. This means that we may have variables named T! + * Flex cannot return the token TIME when it comes across a single T! + * + * We therefore have flex returning the token T_SHARP + * when it comes across 'T#' + */ + TIME '#' interval + {$$ = new duration_c(new time_type_name_c(locloc(@1)), NULL, $3, locloc(@$));} +| TIME '#' '-' interval + {$$ = new duration_c(new time_type_name_c(locloc(@1)), new neg_time_c(locloc(@$)), $4, locloc(@$));} +| T_SHARP interval + {$$ = new duration_c(new time_type_name_c(locloc(@1)), NULL, $2, locloc(@$));} +| T_SHARP '-' interval + {$$ = new duration_c(new time_type_name_c(locloc(@1)), new neg_time_c(locloc(@$)), $3, locloc(@$));} +| SAFETIME '#' interval + {$$ = new duration_c(new safetime_type_name_c(locloc(@1)), NULL, $3, locloc(@$));} +| SAFETIME '#' '-' interval + {$$ = new duration_c(new safetime_type_name_c(locloc(@1)), new neg_time_c(locloc(@$)), $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| TIME interval + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME' and interval in duration."); yynerrs++;} +| TIME '-' interval + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME' and interval in duration."); yynerrs++;} +| TIME '#' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for duration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for duration."); yyclearin;} + yyerrok; + } +| T_SHARP error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no value defined for duration.");} + else {print_err_msg(locf(@2), locl(@2), "invalid value for duration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +interval: + days +| hours +| minutes +| seconds +| milliseconds +; + +integer_d: integer_d_token {$$ = new integer_c($1, locloc(@$));}; +integer_h: integer_h_token {$$ = new integer_c($1, locloc(@$));}; +integer_m: integer_m_token {$$ = new integer_c($1, locloc(@$));}; +integer_s: integer_s_token {$$ = new integer_c($1, locloc(@$));}; +integer_ms: integer_ms_token {$$ = new integer_c($1, locloc(@$));}; + +fixed_point_d: + fixed_point_d_token + {$$ = new fixed_point_c($1, locloc(@$));} +| integer_d +; + +fixed_point_h: + fixed_point_h_token + {$$ = new fixed_point_c($1, locloc(@$));} +| integer_h +; + +fixed_point_m: + fixed_point_m_token + {$$ = new fixed_point_c($1, locloc(@$));} +| integer_m +; + +fixed_point_s: + fixed_point_s_token + {$$ = new fixed_point_c($1, locloc(@$));} +| integer_s +; + +fixed_point_ms: + fixed_point_ms_token + {$$ = new fixed_point_c($1, locloc(@$));} +| integer_ms +; + + +fixed_point: + fixed_point_token + {$$ = new fixed_point_c($1, locloc(@$));} +| integer +; + + +days: +/* fixed_point ('d') */ + fixed_point_d + {$$ = new days_c($1, NULL, locloc(@$));} +/*| integer ('d') ['_'] hours */ +| integer_d hours + {$$ = new days_c($1, $2, locloc(@$));} +| integer_d '_' hours + {$$ = new days_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| integer_d '_' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for hours in duration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for hours in duration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +hours: +/* fixed_point ('h') */ + fixed_point_h + {$$ = new hours_c($1, NULL, locloc(@$));} +/*| integer ('h') ['_'] minutes */ +| integer_h minutes + {$$ = new hours_c($1, $2, locloc(@$));} +| integer_h '_' minutes + {$$ = new hours_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| integer_h '_' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for minutes in duration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for minutes in duration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ + +; + +minutes: +/* fixed_point ('m') */ + fixed_point_m + {$$ = new minutes_c($1, NULL, locloc(@$));} +/*| integer ('m') ['_'] seconds */ +| integer_m seconds + {$$ = new minutes_c($1, $2, locloc(@$));} +| integer_m '_' seconds + {$$ = new minutes_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| integer_m '_' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for seconds in duration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for seconds in duration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +seconds: +/* fixed_point ('s') */ + fixed_point_s + {$$ = new seconds_c($1, NULL, locloc(@$));} +/*| integer ('s') ['_'] milliseconds */ +| integer_s milliseconds + {$$ = new seconds_c($1, $2, locloc(@$));} +| integer_s '_' milliseconds + {$$ = new seconds_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| integer_s '_' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for milliseconds in duration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for milliseconds in duration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +milliseconds: +/* fixed_point ('ms') */ + fixed_point_ms + {$$ = new milliseconds_c($1, locloc(@$));} +; + + + +/************************************/ +/* B 1.2.3.2 - Time of day and Date */ +/************************************/ +time_of_day: + TIME_OF_DAY '#' daytime + {$$ = new time_of_day_c(new tod_type_name_c(locloc(@1)), $3, locloc(@$));} +| SAFETIME_OF_DAY '#' daytime + {$$ = new time_of_day_c(new safetod_type_name_c(locloc(@1)), $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| TIME_OF_DAY daytime + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME_OF_DAY' and daytime in time of day."); yynerrs++;} +| TIME_OF_DAY '#' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for time of day.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for time of day."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +daytime: + day_hour ':' day_minute ':' day_second + {$$ = new daytime_c($1, $3, $5, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| ':' day_minute ':' day_second + {$$ = NULL; print_err_msg(locf(@1), locl(@4), "no value defined for hours in daytime."); yynerrs++;} +| error ':' day_minute ':' day_second + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid value defined for hours in daytime."); yyerrok;} +| day_hour day_minute ':' day_second + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between hours and minutes in daytime."); yynerrs++;} +| day_hour ':' ':' day_second + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no value defined for minutes in daytime."); yynerrs++;} +| day_hour ':' error ':' day_second + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value defined for minutes in daytime."); yyerrok;} +| day_hour ':' day_minute day_second + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "':' missing between minutes and seconds in daytime."); yynerrs++;} +| day_hour ':' day_minute ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@4), locf(@5), "no value defined for seconds in daytime.");} + else {print_err_msg(locf(@5), locl(@5), "invalid value for seconds in daytime."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +day_hour: integer; +day_minute: integer; +day_second: fixed_point; + + +date: + DATE '#' date_literal + {$$ = new date_c(new date_type_name_c(locloc(@1)), $3, locloc(@$));} +| D_SHARP date_literal + {$$ = new date_c(new date_type_name_c(locloc(@1)), $2, locloc(@$));} +| SAFEDATE '#' date_literal + {$$ = new date_c(new safedate_type_name_c(locloc(@1)), $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| DATE date_literal + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'DATE' and date literal in date."); yynerrs++;} +| DATE '#' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for date.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for date."); yyclearin;} + yyerrok; + } +| D_SHARP error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no value defined for date.");} + else {print_err_msg(locf(@2), locl(@2), "invalid value for date."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +date_literal: + year '-' month '-' day + {$$ = new date_literal_c($1, $3, $5, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| '-' month '-' day + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no value defined for year in date literal."); yynerrs++;} +| year month '-' day + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'-' missing between year and month in date literal."); yynerrs++;} +| year '-' '-' day + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no value defined for month in date literal."); yynerrs++;} +| year '-' error '-' day + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value defined for month in date literal."); yyerrok;} +| year '-' month day + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "'-' missing between month and day in date literal."); yynerrs++;} +| year '-' month '-' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@4), locf(@5), "no value defined for day in date literal.");} + else {print_err_msg(locf(@5), locl(@5), "invalid value for day in date literal."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +year: integer; +month: integer; +day: integer; + + +date_and_time: + DATE_AND_TIME '#' date_literal '-' daytime + {$$ = new date_and_time_c(new dt_type_name_c(locloc(@1)), $3, $5, locloc(@$));} +| SAFEDATE_AND_TIME '#' date_literal '-' daytime + {$$ = new date_and_time_c(new safedt_type_name_c(locloc(@1)), $3, $5, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| DATE_AND_TIME date_literal '-' daytime + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'DATE_AND_TIME' and date literal in date and time."); yynerrs++;} +| DATE_AND_TIME '#' '-' daytime + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no value defined for date literal in date and time."); yynerrs++;} +| DATE_AND_TIME '#' error '-' daytime + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value for date literal in date and time."); yyerrok;} +| DATE_AND_TIME '#' date_literal daytime + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "'-' missing between date literal and daytime in date and time."); yynerrs++;} +| DATE_AND_TIME '#' date_literal '-' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@4), locf(@5), "no value defined for daytime in date and time.");} + else {print_err_msg(locf(@5), locl(@5), "invalid value for daytime in date and time."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + + + + +/**********************/ +/* B 1.3 - Data Types */ +/**********************/ +/* Strangely, the following symbol does seem to be required! */ +/* +data_type_name: + non_generic_type_name +| generic_type_name +; +*/ + +non_generic_type_name: + elementary_type_name +| derived_type_name +; + + + +/***********************************/ +/* B 1.3.1 - Elementary Data Types */ +/***********************************/ + /******************************************************/ + /* SAFExxxx Symbols defined in */ + /* "Safety Software Technical Specification, */ + /* Part 1: Concepts and Function Blocks, */ + /* Version 1.0 – Official Release" */ + /* by PLCopen - Technical Committee 5 - 2006-01-31 */ + /******************************************************/ + +elementary_type_name: + numeric_type_name +| date_type_name +| bit_string_type_name +| elementary_string_type_name +| TIME {$$ = new time_type_name_c(locloc(@$));} +| BOOL {$$ = new bool_type_name_c(locloc(@$));} +/* NOTE: see note under the B 1.2.1 section of token + * and grouping type definition for reason why BOOL + * was added to this definition. + */ +| SAFETIME {$$ = new safetime_type_name_c(locloc(@$));} +| SAFEBOOL {$$ = new safebool_type_name_c(locloc(@$));} +; + +numeric_type_name: + integer_type_name +| real_type_name +; + +integer_type_name: + signed_integer_type_name +| unsigned_integer_type_name +; + +signed_integer_type_name: + SINT {$$ = new sint_type_name_c(locloc(@$));} +| INT {$$ = new int_type_name_c(locloc(@$));} +| DINT {$$ = new dint_type_name_c(locloc(@$));} +| LINT {$$ = new lint_type_name_c(locloc(@$));} +| SAFESINT {$$ = new safesint_type_name_c(locloc(@$));} +| SAFEINT {$$ = new safeint_type_name_c(locloc(@$));} +| SAFEDINT {$$ = new safedint_type_name_c(locloc(@$));} +| SAFELINT {$$ = new safelint_type_name_c(locloc(@$));} +; + +unsigned_integer_type_name: + USINT {$$ = new usint_type_name_c(locloc(@$));} +| UINT {$$ = new uint_type_name_c(locloc(@$));} +| UDINT {$$ = new udint_type_name_c(locloc(@$));} +| ULINT {$$ = new ulint_type_name_c(locloc(@$));} +| SAFEUSINT {$$ = new safeusint_type_name_c(locloc(@$));} +| SAFEUINT {$$ = new safeuint_type_name_c(locloc(@$));} +| SAFEUDINT {$$ = new safeudint_type_name_c(locloc(@$));} +| SAFEULINT {$$ = new safeulint_type_name_c(locloc(@$));} +; + +real_type_name: + REAL {$$ = new real_type_name_c(locloc(@$));} +| LREAL {$$ = new lreal_type_name_c(locloc(@$));} +| SAFEREAL {$$ = new safereal_type_name_c(locloc(@$));} +| SAFELREAL {$$ = new safelreal_type_name_c(locloc(@$));} +; + +date_type_name: + DATE {$$ = new date_type_name_c(locloc(@$));} +| TIME_OF_DAY {$$ = new tod_type_name_c(locloc(@$));} +| TOD {$$ = new tod_type_name_c(locloc(@$));} +| DATE_AND_TIME {$$ = new dt_type_name_c(locloc(@$));} +| DT {$$ = new dt_type_name_c(locloc(@$));} +| SAFEDATE {$$ = new safedate_type_name_c(locloc(@$));} +| SAFETIME_OF_DAY {$$ = new safetod_type_name_c(locloc(@$));} +| SAFETOD {$$ = new safetod_type_name_c(locloc(@$));} +| SAFEDATE_AND_TIME {$$ = new safedt_type_name_c(locloc(@$));} +| SAFEDT {$$ = new safedt_type_name_c(locloc(@$));} +; + + +bit_string_type_name: + BYTE {$$ = new byte_type_name_c(locloc(@$));} +| WORD {$$ = new word_type_name_c(locloc(@$));} +| DWORD {$$ = new dword_type_name_c(locloc(@$));} +| LWORD {$$ = new lword_type_name_c(locloc(@$));} +| SAFEBYTE {$$ = new safebyte_type_name_c(locloc(@$));} +| SAFEWORD {$$ = new safeword_type_name_c(locloc(@$));} +| SAFEDWORD {$$ = new safedword_type_name_c(locloc(@$));} +| SAFELWORD {$$ = new safelword_type_name_c(locloc(@$));} +/* NOTE: see note under the B 1.2.1 section of token + * and grouping type definition for reason why the BOOL + * was omitted from this definition. + */ +; + + +/* Helper symbol to concentrate the instantiation + * of STRING and WSTRING into a single location. + * + * These two elements show up in several other rules, + * but we want to create the equivalent abstract syntax + * in a single location of this file, in order to make + * possible future changes easier to edit... + */ +elementary_string_type_name: + STRING {$$ = new string_type_name_c(locloc(@$));} +| WSTRING {$$ = new wstring_type_name_c(locloc(@$));} +| SAFESTRING {$$ = new safestring_type_name_c(locloc(@$));} +| SAFEWSTRING {$$ = new safewstring_type_name_c(locloc(@$));} +; + + + +/********************************/ +/* B 1.3.2 - Generic data types */ +/********************************/ +/* Strangely, the following symbol does not seem to be required! */ +/* +generic_type_name: + ANY +| ANY_DERIVED +| ANY_ELEMENTARY +| ANY_MAGNITUDE +| ANY_NUM +| ANY_REAL +| ANY_INT +| ANY_BIT +| ANY_STRING +| ANY_DATE +; +*/ + + +/********************************/ +/* B 1.3.3 - Derived data types */ +/********************************/ + +derived_type_name: + single_element_type_name +| prev_declared_array_type_name +| prev_declared_structure_type_name +| prev_declared_string_type_name +; + +single_element_type_name: + prev_declared_simple_type_name +/* Include the following if arrays of function blocks are to be allowed! + * Since the standard does not allow them, + * we leave it commented out for the time being... + */ +//| prev_declared_derived_function_block_name +| prev_declared_subrange_type_name +| prev_declared_enumerated_type_name +; + +/* NOTE: in order to remove a reduce/reduce conflict, + * all occurences of simple_type_name, etc... + * have been replaced with identifier! + */ +/* +simple_type_name: identifier; +subrange_type_name: identifier; +enumerated_type_name: identifier; +array_type_name: identifier; +structure_type_name: identifier; +*/ + +data_type_declaration: + TYPE type_declaration_list END_TYPE + {$$ = new data_type_declaration_c($2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| TYPE END_TYPE + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no data type declared in data type(s) declaration."); yynerrs++;} +| TYPE error type_declaration_list END_TYPE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'TYPE' in data type(s) declaration."); yyerrok;} +| TYPE type_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed data type(s) declaration."); yyerrok;} +| TYPE error END_TYPE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in data type(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for data_type_declaration */ +type_declaration_list: + type_declaration ';' + {$$ = new type_declaration_list_c(locloc(@$)); $$->add_element($1);} +| type_declaration_list type_declaration ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new type_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid data type declaration."); yyerrok;} +| type_declaration error + {$$ = new type_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of data type declaration."); yyerrok;} +| type_declaration_list type_declaration error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of data type declaration."); yyerrok;} +| type_declaration_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid data type declaration."); yyerrok;} +| type_declaration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after data type declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +type_declaration: + single_element_type_declaration +| array_type_declaration +| structure_type_declaration +| string_type_declaration +; + +single_element_type_declaration: + simple_type_declaration +| subrange_type_declaration +| enumerated_type_declaration +; + +simple_type_declaration: +/* simple_type_name ':' simple_spec_init */ + identifier ':' simple_spec_init + {$$ = new simple_type_declaration_c($1, $3, locloc(@$)); + library_element_symtable.insert($1, prev_declared_simple_type_name_token); + } +/* ERROR_CHECK_BEGIN */ +| error ':' simple_spec_init + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for data type declaration.");yyerrok;} +| identifier simple_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in simple type declaration."); yynerrs++;} +| identifier ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in data type declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in data type declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +simple_spec_init: + simple_specification + /* The following commented line was changed to the + * next two lines so that we wouldn't + * have the first element of a simple_spec_init_c() + * pointing to another simple_spec_init_c! + */ +/* +| simple_specification ASSIGN constant + {$$ = new simple_spec_init_c($1, $3);} +*/ +| elementary_type_name ASSIGN constant + {$$ = new simple_spec_init_c($1, $3, locloc(@$));} +| prev_declared_simple_type_name ASSIGN constant + {$$ = new simple_spec_init_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| elementary_type_name constant + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in specification with initialization."); yynerrs++;} +| prev_declared_simple_type_name constant + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in specification with initialization."); yynerrs++;} +| elementary_type_name ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in specification with initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid initial value in specification with initialization."); yyclearin;} + yyerrok; + } +| prev_declared_simple_type_name ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in specification with initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid initial value in specification with initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* When converting to C/C++, we need to know whether + * the elementary_type_name is being used in a variable + * declaration or elsewhere (ex. declaration of a derived + * type), so the abstract syntax has the elementary_type_name + * wrapped inside a simple_spec_init_c. + * The exact same thing occurs with prev_declared_simple_type_name. + * + * This is why in the definition of simple_spec_init, + * simple_specification was brocken up into its + * constituent components... + */ +simple_specification: +// elementary_type_name | simple_type_name + elementary_type_name + {$$ = new simple_spec_init_c($1, NULL, locloc(@$));} +| prev_declared_simple_type_name + {$$ = new simple_spec_init_c($1, NULL, locloc(@$));} +; + + +subrange_type_declaration: +/* subrange_type_name ':' subrange_spec_init */ + identifier ':' subrange_spec_init + {$$ = new subrange_type_declaration_c($1, $3, locloc(@$)); + library_element_symtable.insert($1, prev_declared_subrange_type_name_token); + } +/* ERROR_CHECK_BEGIN */ +| error ':' subrange_spec_init + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for subrange type declaration."); yyerrok;} +| identifier subrange_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in subrange type declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +subrange_spec_init: + subrange_specification + {$$ = new subrange_spec_init_c($1, NULL, locloc(@$));} +| subrange_specification ASSIGN signed_integer + {$$ = new subrange_spec_init_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| subrange_specification signed_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in subrange specification with initialization."); yynerrs++;} +| subrange_specification ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in subrange specification with initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid initial value in subrange specification with initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +subrange_specification: + integer_type_name '(' subrange ')' + {$$ = new subrange_specification_c($1, $3, locloc(@$));} +| prev_declared_subrange_type_name + {$$ = new subrange_specification_c($1, NULL, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| integer_type_name '(' ')' + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no subrange defined in subrange specification."); yynerrs++;} +| integer_type_name '(' error ')' + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid subrange defined in subrange specification."); yyerrok;} +| integer_type_name '(' subrange error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing after subrange defined in subrange specification."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +subrange: + signed_integer DOTDOT signed_integer + {$$ = new subrange_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| signed_integer signed_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'..' missing between bounds in subrange definition."); yynerrs++;} +| signed_integer DOTDOT error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for upper bound in subrange definition.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for upper bound in subrange definition."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +enumerated_type_declaration: +/* enumerated_type_name ':' enumerated_spec_init */ + identifier ':' enumerated_spec_init + {$$ = new enumerated_type_declaration_c($1, $3, locloc(@$)); + library_element_symtable.insert($1, prev_declared_enumerated_type_name_token); + } +/* ERROR_CHECK_BEGIN */ +| error ':' enumerated_spec_init + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for enumerated type declaration."); yyerrok;} +| identifier enumerated_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in enumerated type declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +enumerated_spec_init: + enumerated_specification + {$$ = new enumerated_spec_init_c($1, NULL, locloc(@$));} +| enumerated_specification ASSIGN enumerated_value + {$$ = new enumerated_spec_init_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| enumerated_specification enumerated_value + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in enumerated specification with initialization."); yynerrs++;} +| enumerated_specification ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined in enumerated specification with initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value in enumerated specification with initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +enumerated_specification: + '(' enumerated_value_list ')' + {$$ = $2;} +| prev_declared_enumerated_type_name +/* ERROR_CHECK_BEGIN */ +| '(' ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no enumerated value list defined in enumerated specification."); yynerrs++;} +| '(' error ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid enumerated value list defined in enumerated specification.");yyerrok;} +| '(' enumerated_value_list error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of enumerated specification."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for enumerated_specification */ +enumerated_value_list: + enumerated_value + {$$ = new enumerated_value_list_c(locloc(@$)); $$->add_element($1);} +| enumerated_value_list ',' enumerated_value + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| enumerated_value_list enumerated_value + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in enumerated value list.");} +| enumerated_value_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined in enumerated value list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value in enumerated value list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +enumerated_value: + identifier + {$$ = new enumerated_value_c(NULL, $1, locloc(@$));} +| prev_declared_enumerated_type_name '#' any_identifier + {$$ = new enumerated_value_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| prev_declared_enumerated_type_name any_identifier + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between enumerated type name and value in enumerated literal."); yynerrs++;} +| prev_declared_enumerated_type_name '#' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for enumerated literal.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for enumerated literal."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +/* +enumerated_value_without_identifier: + prev_declared_enumerated_type_name '#' any_identifier + {$$ = new enumerated_value_c($1, $3, locloc(@$));} +; +*/ + + +array_type_declaration: +/* array_type_name ':' array_spec_init */ + identifier ':' array_spec_init + {$$ = new array_type_declaration_c($1, $3, locloc(@$)); + library_element_symtable.insert($1, prev_declared_array_type_name_token); + } +/* ERROR_CHECK_BEGIN */ +| identifier array_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in array type declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +array_spec_init: + array_specification + {$$ = new array_spec_init_c($1, NULL, locloc(@$));} +| array_specification ASSIGN array_initialization + {$$ = new array_spec_init_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| array_specification array_initialization + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in array specification with initialization."); yynerrs++;} +| array_specification ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in array specification with initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid initial value in array specification with initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +array_specification: + prev_declared_array_type_name +| ARRAY '[' array_subrange_list ']' OF non_generic_type_name + {$$ = new array_specification_c($3, $6, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| ARRAY array_subrange_list ']' OF non_generic_type_name + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'[' missing before subrange list in array specification."); yynerrs++;} +| ARRAY '[' ']' OF non_generic_type_name + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no subrange list defined in array specification."); yynerrs++;} +| ARRAY '[' error ']' OF non_generic_type_name + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid subrange list defined in array specification."); yyerrok;} +| ARRAY OF non_generic_type_name + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no subrange list defined in array specification."); yynerrs++;} +| ARRAY error OF non_generic_type_name + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid subrange list defined in array specification."); yyerrok;} +| ARRAY '[' array_subrange_list OF non_generic_type_name + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "']' missing after subrange list in array specification."); yynerrs++;} +| ARRAY '[' array_subrange_list ']' non_generic_type_name + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "'OF' missing between subrange list and item type name in array specification."); yynerrs++;} +| ARRAY '[' array_subrange_list ']' OF error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no item data type defined in array specification.");} + else {print_err_msg(locf(@3), locl(@3), "invalid item data type in array specification."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* helper symbol for array_specification */ +array_subrange_list: + subrange + {$$ = new array_subrange_list_c(locloc(@$)); $$->add_element($1);} +| array_subrange_list ',' subrange + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| array_subrange_list subrange + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in subrange list."); yynerrs++;} +| array_subrange_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no subrange defined in subrange list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid subrange in subrange list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +array_initialization: + '[' array_initial_elements_list ']' + {$$ = $2;} +/* ERROR_CHECK_BEGIN */ +| '[' ']' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no initial values list defined in array initialization."); yynerrs++;} +| '[' error ']' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid initial values list defined in array initialization."); yyerrok;} +| '[' array_initial_elements_list error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "']' missing at the end of array initialization."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* helper symbol for array_initialization */ +array_initial_elements_list: + array_initial_elements + {$$ = new array_initial_elements_list_c(locloc(@$)); $$->add_element($1);} +| array_initial_elements_list ',' array_initial_elements + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN +| array_initial_elements_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no array initial value in array initial values list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid array initial value in array initial values list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +array_initial_elements: + array_initial_element +| integer '(' ')' +| integer '(' array_initial_element ')' + {$$ = new array_initial_elements_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| integer '(' error ')' + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid array initial value in array initial values list."); yyerrok;} +| integer '(' array_initial_element error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of array initial value in array initial values list."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +array_initial_element: + constant +| enumerated_value +| structure_initialization +| array_initialization +; + + + +structure_type_declaration: +/* structure_type_name ':' structure_specification */ + identifier ':' structure_specification + {$$ = new structure_type_declaration_c($1, $3, locloc(@$)); + library_element_symtable.insert($1, prev_declared_structure_type_name_token); + } +/* ERROR_CHECK_BEGIN */ +| identifier structure_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in structure type declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +structure_specification: + structure_declaration +| initialized_structure +; + + +initialized_structure: + prev_declared_structure_type_name + {$$ = new initialized_structure_c($1, NULL, locloc(@$));} +| prev_declared_structure_type_name ASSIGN structure_initialization + {$$ = new initialized_structure_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| prev_declared_structure_type_name structure_initialization + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in structure specification with initialization."); yynerrs++;} +| prev_declared_structure_type_name ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined in structure specification with initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value in structure specification with initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +structure_declaration: + STRUCT structure_element_declaration_list END_STRUCT + {$$ = $2;} +/* ERROR_CHECK_BEGIN */ +| STRUCT END_STRUCT + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no structure element declared in structure type declaration."); yynerrs++;} +| STRUCT error structure_element_declaration_list END_STRUCT + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'STRUCT' in structure type declaration."); yyerrok;} +| STRUCT structure_element_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed structure type declaration."); yyerrok;} +| STRUCT error END_STRUCT + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in structure type declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for structure_declaration */ +structure_element_declaration_list: + structure_element_declaration ';' + {$$ = new structure_element_declaration_list_c(locloc(@$)); $$->add_element($1);} +| structure_element_declaration_list structure_element_declaration ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new structure_element_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid structure element declaration."); yyerrok;} +| structure_element_declaration error + {$$ = new structure_element_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of structure element declaration."); yyerrok;} +| structure_element_declaration_list structure_element_declaration error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of structure element declaration."); yyerrok;} +| structure_element_declaration_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid structure element declaration."); yyerrok;} +| structure_element_declaration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after structure element declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +structure_element_declaration: + structure_element_name ':' simple_spec_init + {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} +| structure_element_name ':' subrange_spec_init + {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} +| structure_element_name ':' enumerated_spec_init + {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} +| structure_element_name ':' array_spec_init + {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} +| structure_element_name ':' initialized_structure + {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| structure_element_name simple_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and simple specification."); yynerrs++;} +| structure_element_name subrange_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and subrange specification."); yynerrs++;} +| structure_element_name enumerated_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and enumerated specification."); yynerrs++;} +| structure_element_name array_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and array specification."); yynerrs++;} +| structure_element_name initialized_structure + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and structure specification."); yynerrs++;} +| structure_element_name ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in structure element declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in structure element declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +structure_element_name: any_identifier; + + +structure_initialization: + '(' structure_element_initialization_list ')' + {$$ = $2;} +/* ERROR_CHECK_BEGIN */ +| '(' error ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid structure element initialization list in structure initialization."); yyerrok;} +| '(' structure_element_initialization_list error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "expecting ')' at the end of structure element initialization list in structure initialization."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for structure_initialization */ +structure_element_initialization_list: + structure_element_initialization + {$$ = new structure_element_initialization_list_c(locloc(@$)); $$->add_element($1);} +| structure_element_initialization_list ',' structure_element_initialization + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN +| structure_element_initialization_list structure_element_initialization + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in structure element initialization list in structure initialization."); yynerrs++;} +| structure_element_initialization_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no structure element initialization defined in structure initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid structure element initialization in structure initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +structure_element_initialization: + structure_element_name ASSIGN constant + {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} +| structure_element_name ASSIGN enumerated_value + {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} +| structure_element_name ASSIGN array_initialization + {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} +| structure_element_name ASSIGN structure_initialization + {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| structure_element_name constant + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in structure element initialization."); yynerrs++;} +| structure_element_name enumerated_value + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in enumerated structure element initialization."); yynerrs++;} +| structure_element_name array_initialization + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in array structure element initialization."); yynerrs++;} +| structure_element_name structure_initialization + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in structured structure element initialization."); yynerrs++;} +| structure_element_name ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in structured structure element initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid initial value in structured structure element initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* NOTE: in order to remove a reduce/reduce conflict, + * all occurences of string_type_name + * have been replaced with identifier! + */ +/* +string_type_name: identifier; +*/ + +string_type_declaration: +/* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */ + identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init + {$$ = new string_type_declaration_c($1, $3, $4, $5, locloc(@$)); + library_element_symtable.insert($1, prev_declared_string_type_name_token); + } +; + + +/* helper symbol for string_type_declaration */ +string_type_declaration_size: + '[' integer ']' + {$$ = $2;} +/* REMOVED !! */ +//| /* empty */ +// {$$ = NULL;} +; +/* The syntax contains a reduce/reduce conflict. + * The optional '[' ']' + * has been changed to become mandatory to remove the conflict. + * + * The conflict arises because + * new_str_type : STRING := "hello!" + * may be reduced to a string_type_declaration OR + * a simple_type_declaration. + * + * Our change forces it to be reduced to a + * simple_type_declaration! + * We chose this option because changing the definition + * of simple_spec_init would force us to change all the other + * rules in which it appears. The change we made has no + * side-effects! + */ + +/* helper symbol for string_type_declaration */ +string_type_declaration_init: + /* empty */ + {$$ = NULL;} +| ASSIGN character_string + {$$ = $2;} +; + + + +/*********************/ +/* B 1.4 - Variables */ +/*********************/ +/* NOTE: The standard is erroneous in it's definition of 'variable' because: + * - The standard considers 'ENO' as a keyword... + * - ...=> which means that it may never be parsed as an 'identifier'... + * - ...=> and therefore may never be used as the name of a variable inside an expression. + * - However, a function/FB must be able to assign the ENO parameter + * it's value, doing it in an assignment statement, and therefore using the 'ENO' + * character sequence as an identifier! + * The obvious solution is to also allow the ENO keyword to be + * used as the name of a variable. Note that this variable may be used + * even though it is not explicitly declared as a function/FB variable, + * as the standard requires us to define it implicitly in this case! + * There are three ways of achieving this: + * (i) simply not define EN and ENO as keywords in flex (lexical analyser) + * and let them be considered 'identifiers'. Aditionally, add some code + * so that if they are not explicitly declared, we add them automatically to + * the declaration of each Functions and FB, where they would then be parsed + * as a previously_declared_variable. + * This approach has the advantage the EN and ENO would automatically be valid + * in every location where it needs to be valid, namely in the explicit declaration + * of these same variables, or when they are used within expressions. + * However, this approach has the drawback that + * EN and ENO could then also be used anywhere a standard identifier is allowed, + * including in the naming of Functions, FBs, Programs, Configurations, Resources, + * SFC Actions, SFC Steps, etc... + * This would mean that we would then have to add a lexical analysis check + * within the bison code (syntax analyser) to all the above constructs to make sure + * that the identifier being used is not EN or ENO. + * (ii) The other approach is to define EN and ENO as keywords / tokens in flex + * (lexical analyser) and then change the syntax in bison to acomodate + * these tokens wherever they could correctly appear. + * This has the drawback that we need to do some changes to the synax defintion. + * (iii) Yet a another option is to mix the above two methods. + * Define EN and ENO as tokens in flex, but change (only) the syntax for + * variable declaration to allow these tokens to also be used in declaring variables. + * From this point onwards these tokens are then considered a previously_declared_variable, + * since flex will first check for this before even checking for tokens. + * + * I (Mario) cuurretnly (2011) believe the cleanest method of achieving this goal + * is to use option (iii) + * However, considering that: + * - I have already previously implemented option (ii); + * - option (iii) requires that flex parse the previously_declared_variable + * before parsing any token. We already support this (remeber that this is + * used mainly to allow some IL operators as well as PRIORITY, etc. tokens + * to be used as identifiers, since the standard does not define them as keywords), + * but this part of the code in flex is often commented out as usually people do not expect + * us to follow the standard in the strict sense, but rather consider those + * tokens as keywords; + * considering the above, we currently carry on using option (ii). + */ +variable: + symbolic_variable +| prev_declared_direct_variable +| eno_identifier + {$$ = new symbolic_variable_c($1, locloc(@$));} +; + + +symbolic_variable: +/* NOTE: To be entirely correct, variable_name must be replacemed by + * prev_declared_variable_name | prev_declared_fb_name | prev_declared_global_var_name + */ + prev_declared_fb_name + {$$ = new symbolic_variable_c($1, locloc(@$));} +| prev_declared_global_var_name + {$$ = new symbolic_variable_c($1, locloc(@$));} +| prev_declared_variable_name + {$$ = new symbolic_variable_c($1, locloc(@$));} +| multi_element_variable +/* +| identifier + {$$ = new symbolic_variable_c($1, locloc(@$));} +*/ +; + + +/* NOTE: in section B 1.7, when configuring a program, symbolic_variable + * is used. Nevertheless, during the parsing of a configuration, + * the variables in question are out of scope, so we should + * be allowing any_identifier instead of prev_declared_variable_name! + * + * We therefore need a new any_symbolic_variable construct that + * allows the use of any_identifier instead of previously declared + * variables, function blocks, etc... + */ +any_symbolic_variable: +// variable_name -> replaced by any_identifier + any_identifier + {$$ = new symbolic_variable_c($1, locloc(@$));} +| any_multi_element_variable +; + + +/* for yet undeclared variable names ! */ +variable_name: identifier; + + + + + +/********************************************/ +/* B.1.4.1 Directly Represented Variables */ +/********************************************/ +prev_declared_direct_variable: prev_declared_direct_variable_token {$$ = new direct_variable_c($1, locloc(@$));}; + + + + +/*************************************/ +/* B.1.4.2 Multi-element Variables */ +/*************************************/ +multi_element_variable: + array_variable +| structured_variable +; + +/* please see note above any_symbolic_variable */ +any_multi_element_variable: + any_array_variable +| any_structured_variable +; + + +array_variable: + subscripted_variable '[' subscript_list ']' + {$$ = new array_variable_c($1, $3, locloc(@$));} +; + +/* please see note above any_symbolic_variable */ +any_array_variable: + any_subscripted_variable '[' subscript_list ']' + {$$ = new array_variable_c($1, $3, locloc(@$));} +; + + +subscripted_variable: + symbolic_variable +; + + +/* please see note above any_symbolic_variable */ +any_subscripted_variable: + any_symbolic_variable +; + + +subscript_list: + subscript + {$$ = new subscript_list_c(locloc(@$)); $$->add_element($1);} +| subscript_list ',' subscript + {$$ = $1; $$->add_element($3);} +; + + +subscript: expression; + + +structured_variable: + record_variable '.' field_selector + {$$ = new structured_variable_c($1, $3, locloc(@$));} +; + + +/* please see note above any_symbolic_variable */ +any_structured_variable: + any_record_variable '.' field_selector + {$$ = new structured_variable_c($1, $3, locloc(@$));} +; + + + +record_variable: + symbolic_variable +; + + +/* please see note above any_symbolic_variable */ +any_record_variable: + any_symbolic_variable +; + + +field_selector: + any_identifier +| eno_identifier +; + + + + + + +/******************************************/ +/* B 1.4.3 - Declaration & Initialisation */ +/******************************************/ +input_declarations: + VAR_INPUT input_declaration_list END_VAR + {$$ = new input_declarations_c(NULL, $2, new explicit_definition_c(), locloc(@$));} +| VAR_INPUT RETAIN input_declaration_list END_VAR + {$$ = new input_declarations_c(new retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} +| VAR_INPUT NON_RETAIN input_declaration_list END_VAR + {$$ = new input_declarations_c(new non_retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR_INPUT END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in input variable(s) declaration."); yynerrs++;} +| VAR_INPUT RETAIN END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive input variable(s) declaration."); yynerrs++;} +| VAR_INPUT NON_RETAIN END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in non-retentive input variable(s) declaration."); yynerrs++;} +| VAR_INPUT error input_declaration_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_INPUT' in input variable(s) declaration."); yyerrok;} +| VAR_INPUT RETAIN error input_declaration_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive input variable(s) declaration."); yyerrok;} +| VAR_INPUT NON_RETAIN error input_declaration_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive input variable(s) declaration."); yyerrok;} +| VAR_INPUT input_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed input variable(s) declaration."); yyerrok;} +| VAR_INPUT RETAIN input_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive input variable(s) declaration."); yyerrok;} +| VAR_INPUT NON_RETAIN input_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed non-retentive input variable(s) declaration."); yyerrok;} +| VAR_INPUT error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in input variable(s) declaration."); yyerrok;} +| VAR_INPUT RETAIN error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in retentive input variable(s) declaration."); yyerrok;} +| VAR_INPUT NON_RETAIN error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in non-retentive input variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for input_declarations */ +input_declaration_list: + input_declaration ';' + {$$ = new input_declaration_list_c(locloc(@$)); $$->add_element($1);} +| input_declaration_list input_declaration ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new input_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid input variable(s) declaration."); yyerrok;} +| input_declaration error + {$$ = new input_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of input variable(s) declaration."); yyerrok;} +| input_declaration_list input_declaration error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of input variable(s) declaration."); yyerrok;} +| input_declaration_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid input variable(s) declaration."); yyerrok;} +| input_declaration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after input variable(s) declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +/* NOTE: The formal definition of 'input_declaration' as defined in the standard is erroneous, + * as it does not allow a user defined 'EN' input parameter. However, + * The semantic description of the languages clearly states that this is allowed. + * We have added the 'en_param_declaration' clause to cover for this. + */ +input_declaration: + var_init_decl +| edge_declaration +| en_param_declaration +; + + +edge_declaration: + var1_list ':' BOOL R_EDGE + {$$ = new edge_declaration_c(new raising_edge_option_c(locloc(@3)), $1, locloc(@$));} +| var1_list ':' BOOL F_EDGE + {$$ = new edge_declaration_c(new falling_edge_option_c(locloc(@3)), $1, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list BOOL R_EDGE + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in edge declaration."); yynerrs++;} +| var1_list BOOL F_EDGE + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in edge declaration."); yynerrs++;} +| var1_list ':' BOOL R_EDGE F_EDGE + {$$ = NULL; print_err_msg(locl(@5), locf(@5), "'R_EDGE' and 'F_EDGE' can't be present at the same time in edge declaration."); yynerrs++;} +| var1_list ':' BOOL F_EDGE R_EDGE + {$$ = NULL; print_err_msg(locl(@5), locf(@5), "'R_EDGE' and 'F_EDGE' can't be present at the same time in edge declaration."); yynerrs++;} +| var1_list ':' R_EDGE + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in edge declaration."); yynerrs++;} +| var1_list ':' F_EDGE + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in edge declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +/* NOTE: The formal definition of the standard is erroneous, as it simply does not + * consider the EN and ENO keywords! + * The semantic description of the languages clearly states that these may be + * used in several ways. One of them is to declare an EN input parameter. + * We have added the 'en_param_declaration' clause to cover for this. + * + * Please read the comment above the definition of 'variable' in section B1.4 for details. + */ +en_param_declaration: + en_identifier ':' BOOL ASSIGN boolean_literal + {$$ = new en_param_declaration_c($1, new bool_type_name_c(locloc(@$)), $5, new explicit_definition_c(), locloc(@$));} +| en_identifier ':' BOOL ASSIGN integer + {$$ = new en_param_declaration_c($1, new bool_type_name_c(locloc(@$)), $5, new explicit_definition_c(), locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| en_identifier BOOL ASSIGN boolean_literal + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in EN declaration."); yynerrs++;} +| en_identifier BOOL ASSIGN integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in EN declaration."); yynerrs++;} +| en_identifier ':' ASSIGN boolean_literal + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in EN declaration."); yynerrs++;} +| en_identifier ':' ASSIGN integer + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in EN declaration."); yynerrs++;} +| en_identifier ':' BOOL ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in EN declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in EN declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +var_init_decl: + var1_init_decl +| array_var_init_decl +| structured_var_init_decl +| fb_name_decl +| string_var_declaration +; + + + + +var1_init_decl: + var1_list ':' simple_spec_init + {$$ = new var1_init_decl_c($1, $3, locloc(@$));} +| var1_list ':' subrange_spec_init + {$$ = new var1_init_decl_c($1, $3, locloc(@$));} +| var1_list ':' enumerated_spec_init + {$$ = new var1_init_decl_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list simple_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and simple specification."); yynerrs++;} +| var1_list subrange_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and subrange specification."); yynerrs++;} +| var1_list enumerated_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and enumerated specification."); yynerrs++;} +| var1_list ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in variable declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +/* NOTE: + * The syntax + * variable_name DOTDOT + * is an extension to the standard!!! + * + * In order to be able to handle extensible standard functions + * (i.e. standard functions that may have a variable number of + * input parameters, such as AND(word#33, word#44, word#55, word#66), + * we have extended the acceptable syntax to allow var_name '..' + * in an input variable declaration. + * + * This allows us to parse the declaration of standard + * extensible functions and load their interface definition + * into the abstract syntax tree just like we do to other + * user defined functions. + * This has the advantage that we can later do semantic + * checking of calls to functions (be it a standard or user defined + * function) in (almost) exactly the same way. + * + * Of course, we have a flag that disables this syntax when parsing user + * written code, so we only allow this extra syntax while parsing the + * 'header' file that declares all the standard IEC 61131-3 functions. + */ +var1_list: + variable_name + {$$ = new var1_list_c(locloc(@$)); $$->add_element($1); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + } +| variable_name integer DOTDOT + {$$ = new var1_list_c(locloc(@$)); $$->add_element(new extensible_input_parameter_c($1, $2, locloc(@$))); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + if (!allow_extensible_function_parameters) print_err_msg(locf(@1), locl(@2), "invalid syntax in variable name declaration."); + } + | var1_list ',' variable_name + {$$ = $1; $$->add_element($3); + variable_name_symtable.insert($3, prev_declared_variable_name_token); + } + | var1_list ',' variable_name integer DOTDOT + {$$ = $1; $$->add_element(new extensible_input_parameter_c($3, $4, locloc(@$))); + variable_name_symtable.insert($3, prev_declared_variable_name_token); + if (!allow_extensible_function_parameters) print_err_msg(locf(@1), locl(@2), "invalid syntax in variable name declaration."); + } +/* ERROR_CHECK_BEGIN */ +| var1_list variable_name + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in variable list."); yynerrs++;} +| var1_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no variable name defined in variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid variable name in variable declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +array_var_init_decl: + var1_list ':' array_spec_init + {$$ = new array_var_init_decl_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list array_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and array specification."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +structured_var_init_decl: + var1_list ':' initialized_structure + {$$ = new structured_var_init_decl_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list initialized_structure + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and structured specification."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +/* NOTE: see notes above fb_name_list and var1_list + * for reason why ':' was removed from this rule! + * In essence, to remove a shift/reduce conflict, + * the ':' was moved to var1_list and fb_name_list! + */ +fb_name_decl: +/* fb_name_list ':' function_block_type_name */ + fb_name_list_with_colon function_block_type_name + {$$ = new fb_name_decl_c($1, $2, NULL, locloc(@$));} +/*| fb_name_list ':' function_block_type_name ASSIGN structure_initialization */ +| fb_name_list_with_colon function_block_type_name ASSIGN structure_initialization + {$$ = new fb_name_decl_c($1, $2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| fb_name_list_with_colon ASSIGN structure_initialization + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block type name defined in function block declaration with initialization."); yynerrs++;} +| fb_name_list_with_colon function_block_type_name structure_initialization + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':=' missing in function block declaration with initialization."); yynerrs++;} +| fb_name_list_with_colon function_block_type_name ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no initialization defined in function block declaration.");} + else {print_err_msg(locf(@4), locl(@4), "invalid initialization in function block declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +/* NOTE: In order to remove a reduce/reduce conflict between + * var1_list and fb_name_list, which are identical to each + * other, fb_name_list has been redefined to be a var1_list. + * + * In order to remove a further shift/reduce conflict, var1_list + * is imediately transfomred into var1_list_with_colon + * (i.e. it includes the ':' following the list), which + * means that fb_name_list is built from a + * var1_list_with_colon after all! + */ +/* +fb_name_list: + (* fb_name *) + identifier + {$$ = new fb_name_list_c($1); + variable_name_symtable.insert($1, prev_declared_fb_name_token); + } +(* | fb_name_list ',' fb_name *) +| fb_name_list ',' identifier + {$$ = $1; $$->add_element($3); + variable_name_symtable.insert($3, prev_declared_fb_name_token); + } +; +*/ + +fb_name_list_with_colon: + var1_list_with_colon + {$$ = new fb_name_list_c(locloc(@$)); + /* fill up the new fb_name_list_c object with the references + * contained in the var1_list_c object. + */ + FOR_EACH_ELEMENT(elem, $1, {$$->add_element(elem);}); + delete $1; + /* change the tokens associated with the symbols stored in + * the variable name symbol table from prev_declared_variable_name_token + * to prev_declared_fb_name_token + */ + FOR_EACH_ELEMENT(elem, $$, {variable_name_symtable.set(elem, prev_declared_fb_name_token);}); + } +; + +/* helper symbol for fb_name_list_with_colon */ +var1_list_with_colon: + var1_list ':' +; + + +// fb_name: identifier; + + + +output_declarations: + VAR_OUTPUT var_output_init_decl_list END_VAR + {$$ = new output_declarations_c(NULL, $2, new explicit_definition_c(), locloc(@$));} +| VAR_OUTPUT RETAIN var_output_init_decl_list END_VAR + {$$ = new output_declarations_c(new retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} +| VAR_OUTPUT NON_RETAIN var_output_init_decl_list END_VAR + {$$ = new output_declarations_c(new non_retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR_OUTPUT END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in output variable(s) declaration."); yynerrs++;} +| VAR_OUTPUT RETAIN END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive output variable(s) declaration."); yynerrs++;} +| VAR_OUTPUT NON_RETAIN END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in non-retentive output variable(s) declaration."); yynerrs++;} +| VAR_OUTPUT error var_output_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_OUPUT' in output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT RETAIN error var_output_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT NON_RETAIN error var_output_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT var_output_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT RETAIN var_output_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT NON_RETAIN var_output_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed non-retentive output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT RETAIN error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in retentive output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT NON_RETAIN error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in non-retentive output variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* NOTE: The formal definition of 'var_output_init_decl' as defined in the standard is erroneous, + * as it does not allow a user defined 'ENO' output parameter. However, + * The semantic description of the languages clearly states that this is allowed. + * We have added the 'eno_param_declaration' clause to cover for this. + * + * Please read the comment above the definition of 'variable' in section B1.4 for details. + */ +var_output_init_decl: + var_init_decl +| eno_param_declaration +; + +var_output_init_decl_list: + var_output_init_decl ';' + {$$ = new var_init_decl_list_c(locloc(@$)); $$->add_element($1);} +| var_output_init_decl_list var_output_init_decl ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| var_output_init_decl_list var_output_init_decl error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of variable(s) declaration."); yyerrok;} +| var_output_init_decl_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* NOTE: The formal definition of the standard is erroneous, as it simply does not + * consider the EN and ENO keywords! + * The semantic description of the languages clearly states that these may be + * used in several ways. One of them is to declare an ENO output parameter. + * We have added the 'eno_param_declaration' clause to cover for this. + * + * Please read the comment above the definition of 'variable' in section B1.4 for details. + */ +eno_param_declaration: + eno_identifier ':' BOOL + /* NOTE We do _NOT_ include this variable in the previously_declared_variable symbol table! + * Please read the comment above the definition of 'variable' for the reason for this. + */ + {$$ = new eno_param_declaration_c($1, new bool_type_name_c(locloc(@$)), new explicit_definition_c(), locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| eno_identifier BOOL + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in ENO declaration."); yynerrs++;} +| eno_identifier ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in ENO declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in ENO declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +input_output_declarations: + VAR_IN_OUT var_declaration_list END_VAR + {$$ = new input_output_declarations_c($2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR_IN_OUT END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in in_out variable(s) declaration."); yynerrs++;} +| VAR_IN_OUT error var_declaration_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_IN_OUT' in in_out variable(s) declaration."); yyerrok;} +| VAR_IN_OUT var_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed in_out variable(s) declaration."); yyerrok;} +| VAR_IN_OUT error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in in_out variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + +/* helper symbol for input_output_declarations */ +var_declaration_list: + var_declaration ';' + {$$ = new var_declaration_list_c(locloc(@$)); $$->add_element($1);} +| var_declaration_list var_declaration ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new var_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid variable(s) declaration."); yyerrok;} +| var_declaration error + {$$ = new var_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of variable(s) declaration."); yyerrok;} +| var_declaration_list var_declaration error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of variable(s) declaration."); yyerrok;} +| var_declaration_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid variable(s) declaration."); yyerrok;} +| var_declaration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after variable(s) declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +var_declaration: + temp_var_decl +| fb_name_decl +; + + +temp_var_decl: + var1_declaration +| array_var_declaration +| structured_var_declaration +| string_var_declaration +; + +var1_declaration: + var1_list ':' simple_specification + {$$ = new var1_init_decl_c($1, $3, locloc(@$));} +| var1_list ':' subrange_specification + {$$ = new var1_init_decl_c($1, $3, locloc(@$));} +| var1_list ':' enumerated_specification + {$$ = new var1_init_decl_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list simple_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and simple specification."); yynerrs++;} +| var1_list subrange_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and subrange specification."); yynerrs++;} +| var1_list enumerated_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and enumerated specification."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + + +array_var_declaration: + var1_list ':' array_specification + {$$ = new array_var_declaration_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list array_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and array specification."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +structured_var_declaration: + var1_list ':' prev_declared_structure_type_name + {$$ = new structured_var_declaration_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list prev_declared_structure_type_name + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and structured specification."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +var_declarations: + VAR var_init_decl_list END_VAR + {$$ = new var_declarations_c(NULL, $2, locloc(@$));} +| VAR CONSTANT var_init_decl_list END_VAR + {$$ = new var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in variable(s) declaration."); yynerrs++;} +| VAR CONSTANT END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in constant variable(s) declaration."); yynerrs++;} +| VAR error var_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@3), "unexpected token after 'VAR' in variable(s) declaration."); yyerrok;} +| VAR CONSTANT error var_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant variable(s) declaration."); yyerrok;} +| VAR var_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed variable(s) declaration."); yyerrok;} +| VAR CONSTANT var_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant variable(s) declaration."); yyerrok;} +| VAR error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in variable(s) declaration."); yyerrok;} +| VAR CONSTANT error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +retentive_var_declarations: + VAR RETAIN var_init_decl_list END_VAR + {$$ = new retentive_var_declarations_c($3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR RETAIN END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive variable(s) declaration."); yynerrs++;} +| VAR RETAIN error var_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive variable(s) declaration."); yyerrok;} +| VAR RETAIN var_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive variable(s) declaration."); yyerrok;} +| VAR RETAIN error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in retentive variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +located_var_declarations: + VAR located_var_decl_list END_VAR + {$$ = new located_var_declarations_c(NULL, $2, locloc(@$));} +| VAR CONSTANT located_var_decl_list END_VAR + {$$ = new located_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} +| VAR RETAIN located_var_decl_list END_VAR + {$$ = new located_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));} +| VAR NON_RETAIN located_var_decl_list END_VAR + {$$ = new located_var_declarations_c(new non_retain_option_c(locloc(@2)), $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR NON_RETAIN END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in non-retentive located variable(s) declaration."); yynerrs++;} +| VAR error located_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR' in located variable(s) declaration."); yyerrok;} +| VAR CONSTANT error located_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant located variable(s) declaration."); yyerrok;} +| VAR RETAIN error located_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive located variable(s) declaration."); yyerrok;} +| VAR NON_RETAIN error located_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive located variable(s) declaration."); yyerrok;} +| VAR located_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed located variable(s) declaration."); yyerrok;} +| VAR CONSTANT located_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant located variable(s) declaration."); yyerrok;} +| VAR RETAIN located_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive located variable(s) declaration."); yyerrok;} +| VAR NON_RETAIN located_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed non-retentive located variable(s) declaration."); yyerrok;} +| VAR NON_RETAIN error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in non retentive variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* helper symbol for located_var_declarations */ +located_var_decl_list: + located_var_decl ';' + {$$ = new located_var_decl_list_c(locloc(@$)); $$->add_element($1);} +| located_var_decl_list located_var_decl ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new located_var_decl_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid located variable declaration."); yyerrok;} +| located_var_decl error + {$$ = new located_var_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of located variable declaration."); yyerrok;} +| located_var_decl_list located_var_decl error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of located variable declaration."); yyerrok;} +| located_var_decl_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid located variable declaration."); yyerrok;} +| located_var_decl_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after located variable declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +located_var_decl: + variable_name location ':' located_var_spec_init + {$$ = new located_var_decl_c($1, $2, $4, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + } +| location ':' located_var_spec_init + {$$ = new located_var_decl_c(NULL, $1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| variable_name location located_var_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between located variable location and specification."); yynerrs++;} +| location located_var_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between located variable location and specification."); yynerrs++;} +| variable_name location ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in located variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in located variable declaration."); yyclearin;} + yyerrok; + } +| location ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in located variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in located variable declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + + +external_var_declarations: + VAR_EXTERNAL external_declaration_list END_VAR + {$$ = new external_var_declarations_c(NULL, $2, locloc(@$));} +| VAR_EXTERNAL CONSTANT external_declaration_list END_VAR + {$$ = new external_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR_EXTERNAL END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in external variable(s) declaration."); yynerrs++;} +| VAR_EXTERNAL CONSTANT END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in constant external variable(s) declaration."); yynerrs++;} +| VAR_EXTERNAL error external_declaration_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_EXTERNAL' in external variable(s) declaration."); yyerrok;} +| VAR_EXTERNAL CONSTANT error external_declaration_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant external variable(s) declaration."); yyerrok;} +| VAR_EXTERNAL external_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed external variable(s) declaration."); yyerrok;} +| VAR_EXTERNAL CONSTANT external_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant external variable(s) declaration."); yyerrok;} +| VAR_EXTERNAL error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in external variable(s) declaration."); yyerrok;} +| VAR_EXTERNAL CONSTANT error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant external variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for external_var_declarations */ +external_declaration_list: + external_declaration ';' + {$$ = new external_declaration_list_c(locloc(@$)); $$->add_element($1);} +| external_declaration_list external_declaration ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new external_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid external variable declaration."); yyerrok;} +| external_declaration error + {$$ = new external_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of external variable declaration."); yyerrok;} +| external_declaration_list external_declaration error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of external variable declaration."); yyerrok;} +| external_declaration_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid external variable declaration."); yyerrok;} +| external_declaration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after external variable declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +external_declaration: + global_var_name ':' simple_specification + {$$ = new external_declaration_c($1, $3, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + } +| global_var_name ':' subrange_specification + {$$ = new external_declaration_c($1, $3, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + } +| global_var_name ':' enumerated_specification + {$$ = new external_declaration_c($1, $3, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + } +| global_var_name ':' array_specification + {$$ = new external_declaration_c($1, $3, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + } +| global_var_name ':' prev_declared_structure_type_name + {$$ = new external_declaration_c($1, $3, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + } +| global_var_name ':' function_block_type_name + {$$ = new external_declaration_c($1, $3, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_fb_name_token); + } +/* ERROR_CHECK_BEGIN */ +| global_var_name simple_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and simple specification."); yynerrs++;} +| global_var_name subrange_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and subrange specification."); yynerrs++;} +| global_var_name enumerated_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and enumerated specification."); yynerrs++;} +| global_var_name array_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and array specification."); yynerrs++;} +| global_var_name prev_declared_structure_type_name + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and structured specification."); yynerrs++;} +| global_var_name function_block_type_name + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and function block type specification."); yynerrs++;} +| global_var_name ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in external variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in external variable declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +global_var_name: identifier; + + +global_var_declarations: + VAR_GLOBAL global_var_decl_list END_VAR + {$$ = new global_var_declarations_c(NULL, $2, locloc(@$));} +| VAR_GLOBAL CONSTANT global_var_decl_list END_VAR + {$$ = new global_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} +| VAR_GLOBAL RETAIN global_var_decl_list END_VAR + {$$ = new global_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR_GLOBAL END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in global variable(s) declaration."); yynerrs++;} +| VAR_GLOBAL CONSTANT END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in constant global variable(s) declaration."); yynerrs++;} +| VAR_GLOBAL RETAIN END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive global variable(s) declaration."); yynerrs++;} +| VAR_GLOBAL error global_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_GLOBAL' in global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL CONSTANT error global_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL RETAIN error global_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL global_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL CONSTANT global_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL RETAIN global_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL CONSTANT error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL RETAIN error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant global variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* helper symbol for global_var_declarations */ +global_var_decl_list: + global_var_decl ';' + {$$ = new global_var_decl_list_c(locloc(@$)); $$->add_element($1);} +| global_var_decl_list global_var_decl ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new global_var_decl_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid global variable(s) declaration."); yyerrok;} +| global_var_decl error + {$$ = new global_var_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of global variable(s) declaration."); yyerrok;} +| global_var_decl_list global_var_decl error + {$$ = $1; print_err_msg(locl(@1), locf(@2), "';' missing at end of global variable(s) declaration."); yyerrok;} +| global_var_decl_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid global variable(s) declaration."); yyerrok;} +| global_var_decl_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after global variable(s) declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +global_var_decl: +/* NOTE : This possibility defined in standard has no sense and generate a conflict (disabled) + global_var_spec ':' + {$$ = new global_var_decl_c($1, NULL, locloc(@$));} +*/ + global_var_spec ':' located_var_spec_init + {$$ = new global_var_decl_c($1, $3, locloc(@$));} +| global_var_spec ':' function_block_type_name + {$$ = new global_var_decl_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| global_var_list located_var_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between global variable list and type specification."); yynerrs++;} +| global_var_name location located_var_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between global variable specification and type specification."); yynerrs++;} +| global_var_spec function_block_type_name + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between global variable specification and function block type specification."); yynerrs++;} +| global_var_spec ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in global variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in global variable declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +global_var_spec: + global_var_list {$$ = $1;} +| location + {$$ = new global_var_spec_c(NULL, $1, locloc(@$));} +| global_var_name location + {$$ = new global_var_spec_c($1, $2, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_global_var_name_token); + } +; + + +located_var_spec_init: + simple_spec_init +| subrange_spec_init +| enumerated_spec_init +| array_spec_init +| initialized_structure +| single_byte_string_spec +| double_byte_string_spec +; + + +location: + AT direct_variable_token + {$$ = new location_c(new direct_variable_c($2, locloc(@$)), locloc(@$)); + direct_variable_symtable.insert($2, prev_declared_direct_variable_token); + } +/* ERROR_CHECK_BEGIN */ +| AT error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no location defined in location declaration.");} + else {print_err_msg(locf(@2), locl(@2), "invalid location in global location declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +global_var_list: + global_var_name + {$$ = new global_var_list_c(locloc(@$)); $$->add_element($1); + variable_name_symtable.insert($1, prev_declared_global_var_name_token); + } +| global_var_list ',' global_var_name + {$$ = $1; $$->add_element($3); + variable_name_symtable.insert($3, prev_declared_global_var_name_token); + } +/* ERROR_CHECK_BEGIN */ +| global_var_list global_var_name + {$$ = new global_var_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "',' missing in global variable list."); yynerrs++;} +| global_var_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no variable name defined in global variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid variable name in global variable declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +string_var_declaration: + single_byte_string_var_declaration +| double_byte_string_var_declaration +; + +single_byte_string_var_declaration: + var1_list ':' single_byte_string_spec + {$$ = new single_byte_string_var_declaration_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list single_byte_string_spec + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and string type specification."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +/* NOTE: The constructs + * + * [W]STRING + * and + * [W]STRING ASSIGN single_byte_character_string + * + * were removed as they are already contained + * within a other constructs. + * + * single_byte_string_spec is used in: + * - single_byte_string_var_declaration -> + * -> string_var_declaration ---> var_init_decl + * |--> temp_var_decl + * |--> var2_init_decl + * - located_var_spec_init + * + * STRING [ASSIGN string_constant] -> elementary_string_type_name -> + * -> simple_spec -> simple_specification -> simple_spec_init -> + * -> located_var_spec_init + * + * STRING [ASSIGN string_constant] -> elementary_string_type_name -> + * -> simple_spec -> simple_specification -> simple_spec_init -> + * -> var1_init_decl -> var_init_decl + * + * STRING [ASSIGN string_constant] -> elementary_string_type_name -> + * -> simple_spec -> simple_specification -> simple_spec_init -> + * -> var1_init_decl -> var2_init_decl + * + * STRING [ASSIGN string_constant] -> elementary_string_type_name -> + * -> simple_spec -> simple_specification -> + * -> var1_declaration -> temp_var_decl + */ +single_byte_string_spec: +/* STRING + {$$ = new single_byte_string_spec_c(NULL, NULL);} +*/ + STRING '[' integer ']' + {$$ = new single_byte_string_spec_c(new single_byte_limited_len_string_spec_c(new string_type_name_c(locloc(@1)), $3, locloc(@$)), NULL, locloc(@$));} +/* +| STRING ASSIGN single_byte_character_string + {$$ = new single_byte_string_spec_c($1, NULL, $3, locloc(@$));} +*/ +| STRING '[' integer ']' ASSIGN single_byte_character_string + {$$ = new single_byte_string_spec_c(new single_byte_limited_len_string_spec_c(new string_type_name_c(locloc(@1)), $3, locloc(@$)), $6, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| STRING '[' error ']' + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited string type specification."); yyerrok;} +| STRING '[' error ']' ASSIGN single_byte_character_string + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited string type specification."); yyerrok;} +| STRING '[' ']' + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited string type specification."); yynerrs++;} +| STRING '[' ']' ASSIGN single_byte_character_string + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited string type specification."); yynerrs++;} +| STRING '[' integer error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "expecting ']' after length definition for limited string type specification."); yyerrok;} +| STRING '[' integer ']' single_byte_character_string + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':=' missing before limited string type initialization."); yynerrs++;} +| STRING '[' integer ']' ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@5), locf(@6), "no initial value defined in limited string type initialization.");} + else {print_err_msg(locf(@6), locl(@6), "invalid initial value in limited string type initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +double_byte_string_var_declaration: + var1_list ':' double_byte_string_spec + {$$ = new double_byte_string_var_declaration_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list double_byte_string_spec + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and double byte string type specification."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +double_byte_string_spec: +/* WSTRING + {$$ = new double_byte_string_spec_c($1, NULL, NULL, locloc(@$));} +*/ + WSTRING '[' integer ']' + {$$ = new double_byte_string_spec_c(new double_byte_limited_len_string_spec_c(new wstring_type_name_c(locloc(@1)), $3, locloc(@$)), NULL, locloc(@$));} + +/* +| WSTRING ASSIGN double_byte_character_string + {$$ = new double_byte_string_spec_c($1, NULL, $3, locloc(@$));} +*/ +| WSTRING '[' integer ']' ASSIGN double_byte_character_string + {$$ = new double_byte_string_spec_c(new double_byte_limited_len_string_spec_c(new wstring_type_name_c(locloc(@1)), $3, locloc(@$)), $6, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| WSTRING '[' error ']' + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited double byte string type specification."); yyerrok;} +| WSTRING '[' error ']' ASSIGN single_byte_character_string + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited double byte string type specification."); yyerrok;} +| WSTRING '[' ']' + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited double byte string type specification."); yynerrs++;} +| WSTRING '[' ']' ASSIGN single_byte_character_string + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited double byte string type specification."); yynerrs++;} +| WSTRING '[' integer error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "expecting ']' after length definition for limited double byte string type specification."); yyerrok;} +| WSTRING '[' integer ']' single_byte_character_string + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':=' missing before limited double byte string type initialization."); yynerrs++;} +| WSTRING '[' integer ']' ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@5), locf(@6), "no initial value defined double byte in limited string type initialization.");} + else {print_err_msg(locf(@6), locl(@6), "invalid initial value in limited double byte string type initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +incompl_located_var_declarations: + VAR incompl_located_var_decl_list END_VAR + {$$ = new incompl_located_var_declarations_c(NULL, $2, locloc(@$));} +| VAR RETAIN incompl_located_var_decl_list END_VAR + {$$ = new incompl_located_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));} +| VAR NON_RETAIN incompl_located_var_decl_list END_VAR + {$$ = new incompl_located_var_declarations_c(new non_retain_option_c(locloc(@2)), $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR incompl_located_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed incomplete located variable(s) declaration."); yyerrok;} +| VAR RETAIN incompl_located_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed incomplete retentive located variable(s) declaration."); yyerrok;} +| VAR NON_RETAIN incompl_located_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed incomplete non-retentive located variable(s) declaration."); yyerrok;} +| VAR error incompl_located_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR' in incomplete located variable(s) declaration."); yyerrok;} +| VAR RETAIN error incompl_located_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive located variable(s) declaration."); yyerrok;} +| VAR NON_RETAIN error incompl_located_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive located variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for incompl_located_var_declarations */ +incompl_located_var_decl_list: + incompl_located_var_decl ';' + {$$ = new incompl_located_var_decl_list_c(locloc(@$)); $$->add_element($1);} +| incompl_located_var_decl_list incompl_located_var_decl ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| incompl_located_var_decl error + {$$ = new incompl_located_var_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of incomplete located variable declaration."); yyerrok;} +| incompl_located_var_decl_list incompl_located_var_decl error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of incomplete located variable declaration."); yyerrok;} +| incompl_located_var_decl_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid incomplete located variable declaration."); yyerrok;} +| incompl_located_var_decl_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after incomplete located variable declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +incompl_located_var_decl: + variable_name incompl_location ':' var_spec + {$$ = new incompl_located_var_decl_c($1, $2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| variable_name incompl_location var_spec + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between incomplete located variable and type specification."); yynerrs++; + } +| variable_name incompl_location ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in incomplete located variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in incomplete located variable declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +incompl_location: + AT incompl_location_token + {$$ = new incompl_location_c($2, locloc(@$));} +; + + +var_spec: + simple_specification +| subrange_specification +| enumerated_specification +| array_specification +| prev_declared_structure_type_name +| string_spec +; + + +/* helper symbol for var_spec */ +string_spec: +/* STRING + {$$ = new single_byte_limited_len_string_spec_c($1, NULL, locloc(@$));} +*/ + STRING '[' integer ']' + {$$ = new single_byte_limited_len_string_spec_c(new string_type_name_c(locloc(@1)), $3, locloc(@$));} +/* +| WSTRING + {$$ = new double_byte_limited_len_string_spec_c($1, NULL, locloc(@$));} +*/ +| WSTRING '[' integer ']' + {$$ = new double_byte_limited_len_string_spec_c(new wstring_type_name_c(locloc(@1)), $3, locloc(@$));} +; + + + + +/* intermediate helper symbol for: + * - non_retentive_var_decls + * - var_declarations + */ +var_init_decl_list: + var_init_decl ';' + {$$ = new var_init_decl_list_c(locloc(@$)); $$->add_element($1);} +| var_init_decl_list var_init_decl ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| var_init_decl_list var_init_decl error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of variable(s) declaration."); yyerrok;} +| var_init_decl_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + + +/***********************/ +/* B 1.5.1 - Functions */ +/***********************/ +/* +function_name: + prev_declared_derived_function_name +| standard_function_name +; +*/ + +/* The following rules should be set such as: + * function_name: function_name_no_clashes | function_name_simpleop_clashes | function_name_expression_clashes + * function_name: function_name_no_NOT_clashes | function_name_NOT_clashes; + */ + +function_name_no_clashes: prev_declared_derived_function_name | standard_function_name_no_clashes; +function_name_simpleop_clashes: standard_function_name_simpleop_clashes; +//function_name_expression_clashes: standard_function_name_expression_clashes; + +function_name_no_NOT_clashes: prev_declared_derived_function_name | standard_function_name_no_NOT_clashes; +//function_name_NOT_clashes: standard_function_name_NOT_clashes; + + +/* NOTE: The list of standard function names + * includes the standard functions MOD(), NOT() + * + * Strangely enough, MOD and NOT are reserved keywords, + * so shouldn't be used for function names. + * + * The specification contradicts itself! + * Our workaround is to treat MOD as a token, + * but to include this token as a + * standard_function_name. + * + * The names of all other standard functions get + * preloaded into the library_element_symbol_table + * with the token value of + * standard_function_name_token + * Actually, simply for completeness, MOD is also + * loaded into the library_element_symbol_table, but + * it is irrelevant since flex will catch MOD as a + * token, before it interprets it as an identifier, + * and looks in the library_element_symbol_table to check + * whether it has been previously declared. + * + * NOTE: The same as the above also occurs with the IL + * operators NOT AND OR XOR ADD SUB MUL DIV MOD + * GT GE EQ LT LE NE. + * Note that MOD is once again in the list! + * Anyway, we give these the same treatement as + * MOD, since we are writing a parser for ST and + * IL simultaneously. If this were not the case, + * the ST parser would not need the tokens NOT AND ... + * + * NOTE: Note that 'NOT' is special, as it conflicts + * with two operators: the IL 'NOT' operator, and + * the unary operator 'NOT' in ST!! + * + * NOTE: The IL language is ambiguous, since using NOT, AND, ... + * may be interpreted as either an IL operator, or + * as a standard function call! + * I (Mario) opted to interpret it as an IL operator. + * This requires changing the syntax for IL language + * function calling, to exclude all function with + * names that clash with IL operators. I therefore + * created the constructs + * function_name_without_clashes + * standard_function_name_without_clashes + * to include all function names, except those that clash + * with IL operators. These constructs are only used + * within the IL language! + */ +/* The following rules should be set such as: + * standard_function_name: standard_function_name_no_clashes | standard_function_name_simpleop_clashes | standard_function_name_expression_clashes + * standard_function_name: standard_function_name_no_NOT_clashes | standard_function_name_NOT_clashes; + */ + +/* +standard_function_name: + standard_function_name_no_clashes +| standard_function_name_expression_clashes +| standard_function_name_NOT_clashes +//| standard_function_name_simpleop_only_clashes +; +*/ + +standard_function_name_no_NOT_clashes: + standard_function_name_no_clashes +| standard_function_name_expression_clashes +//| standard_function_name_simpleop_only_clashes +; + +standard_function_name_no_clashes: + standard_function_name_token + {$$ = new identifier_c($1, locloc(@$));} +; + + +standard_function_name_simpleop_clashes: + standard_function_name_NOT_clashes +//| standard_function_name_simpleop_only_clashes +; + +standard_function_name_NOT_clashes: + NOT + {$$ = new identifier_c(strdup("NOT"), locloc(@$));} +; + +/* Add here any other IL simple operators that collide + * with standard function names! + * Don't forget to uncomment the equivalent lines in + * - standard_function_name_simpleop_clashes + * - standard_function_name + * - standard_function_name_no_NOT_clashes + */ +/* +standard_function_name_simpleop_only_clashes: +; +*/ + +standard_function_name_expression_clashes: + AND {$$ = new identifier_c(strdup("AND"), locloc(@$));} +| OR {$$ = new identifier_c(strdup("OR"), locloc(@$));} +| XOR {$$ = new identifier_c(strdup("XOR"), locloc(@$));} +| ADD {$$ = new identifier_c(strdup("ADD"), locloc(@$));} +| SUB {$$ = new identifier_c(strdup("SUB"), locloc(@$));} +| MUL {$$ = new identifier_c(strdup("MUL"), locloc(@$));} +| DIV {$$ = new identifier_c(strdup("DIV"), locloc(@$));} +| MOD {$$ = new identifier_c(strdup("MOD"), locloc(@$));} +| GT {$$ = new identifier_c(strdup("GT"), locloc(@$));} +| GE {$$ = new identifier_c(strdup("GE"), locloc(@$));} +| EQ {$$ = new identifier_c(strdup("EQ"), locloc(@$));} +| LT {$$ = new identifier_c(strdup("LT"), locloc(@$));} +| LE {$$ = new identifier_c(strdup("LE"), locloc(@$));} +| NE {$$ = new identifier_c(strdup("NE"), locloc(@$));} +/* + AND_operator {$$ = il_operator_c_2_identifier_c($1);} +//NOTE: AND2 (corresponding to the source code string '&') does not clash +// with a standard function name, so should be commented out! +//| AND2_operator {$$ = il_operator_c_2_identifier_c($1);} +| OR_operator {$$ = il_operator_c_2_identifier_c($1);} +| XOR_operator {$$ = il_operator_c_2_identifier_c($1);} +| ADD_operator {$$ = il_operator_c_2_identifier_c($1);} +| SUB_operator {$$ = il_operator_c_2_identifier_c($1);} +| MUL_operator {$$ = il_operator_c_2_identifier_c($1);} +| DIV_operator {$$ = il_operator_c_2_identifier_c($1);} +| MOD_operator {$$ = il_operator_c_2_identifier_c($1);} +| GT_operator {$$ = il_operator_c_2_identifier_c($1);} +| GE_operator {$$ = il_operator_c_2_identifier_c($1);} +| EQ_operator {$$ = il_operator_c_2_identifier_c($1);} +| LT_operator {$$ = il_operator_c_2_identifier_c($1);} +| LE_operator {$$ = il_operator_c_2_identifier_c($1);} +| NE_operator {$$ = il_operator_c_2_identifier_c($1);} +*/ +; + + +derived_function_name: + identifier +| prev_declared_derived_function_name + {$$ = $1; + if (!allow_function_overloading) { + fprintf(stderr, "Function overloading not allowed. Invalid identifier %s\n", ((token_c *)($1))->value); + ERROR; + } + } +| AND + {$$ = new identifier_c("AND", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"AND\" not allowed. Invalid identifier\n"); + } +| OR + {$$ = new identifier_c("OR", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"OR\" not allowed. Invalid identifier\n"); + } +| XOR + {$$ = new identifier_c("XOR", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"XOR\" not allowed. Invalid identifier\n"); + } +| NOT + {$$ = new identifier_c("NOT", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"NOT\" not allowed. Invalid identifier\n"); + } +| MOD + {$$ = new identifier_c("MOD", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"MOD\" not allowed. Invalid identifier\n"); + } +; + + +function_declaration: +/* FUNCTION derived_function_name ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ + function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION + {$$ = new function_declaration_c($1, $3, $4, $5, locloc(@$)); + add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + if (allow_function_overloading) { + switch (library_element_symtable.find_value($1)) { + case prev_declared_derived_function_name_token: + /* do nothing, already in map. */ + break; + case BOGUS_TOKEN_ID: + /* Not yet in map. Must insert...*/ + library_element_symtable.insert($1, prev_declared_derived_function_name_token); + break; + default: + /* Already in map but associated with something else other than a funtion name! */ + ERROR; + } + } else { + library_element_symtable.insert($1, prev_declared_derived_function_name_token); + } + } +/* | FUNCTION derived_function_name ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ +| function_name_declaration ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION + {$$ = new function_declaration_c($1, $3, $4, $5, locloc(@$)); + add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + if (allow_function_overloading) { + switch (library_element_symtable.find_value($1)) { + case prev_declared_derived_function_name_token: /* do nothing, already in map. */ break; + case BOGUS_TOKEN_ID: library_element_symtable.insert($1, prev_declared_derived_function_name_token); break; + default: ERROR; + } + } else { + library_element_symtable.insert($1, prev_declared_derived_function_name_token); + } + } +/* ERROR_CHECK_BEGIN */ +| function_name_declaration elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after function name in function declaration."); yynerrs++;} +| function_name_declaration derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after function name in function declaration."); yynerrs++;} +| function_name_declaration ':' io_OR_function_var_declarations_list function_body END_FUNCTION + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no return type defined in function declaration."); yynerrs++;} +| function_name_declaration ':' error io_OR_function_var_declarations_list function_body END_FUNCTION + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid return type defined in function declaration."); yyerrok;} +| function_name_declaration ':' elementary_type_name function_body END_FUNCTION + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared in function declaration."); yynerrs++;} +| function_name_declaration ':' derived_type_name function_body END_FUNCTION + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared in function declaration."); yynerrs++;} +| function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list END_FUNCTION + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no body defined in function declaration."); yynerrs++;} +| function_name_declaration ':' derived_type_name io_OR_function_var_declarations_list END_FUNCTION + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no body defined in function declaration."); yynerrs++;} +| function_name_declaration ':' elementary_type_name END_FUNCTION + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared and body defined in function declaration."); yynerrs++;} +| function_name_declaration ':' derived_type_name END_FUNCTION + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared and body defined in function declaration."); yynerrs++;} +| function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list function_body END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locf(@3), "unclosed function declaration."); yynerrs++;} +| function_name_declaration ':' derived_type_name io_OR_function_var_declarations_list function_body END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed function declaration."); yynerrs++;} +| function_name_declaration error END_FUNCTION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in function declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + +/* helper symbol for function_declaration */ +/* NOTE: due to reduce/reduce conflicts between identifiers + * being reduced to either a variable or an enumerator value, + * we were forced to keep a symbol table of the names + * of all declared variables. Variables are no longer + * created from simple identifier_token, but from + * prev_declared_variable_name_token. + * + * BUT, in functions the function name itself may be used as + * a variable! In order to be able to parse this correctly, + * the token parser (flex) must return a prev_declared_variable_name_token + * when it comes across the function name, while parsing + * the function itself. + * We do this by inserting the function name into the variable + * symbol table, and having flex return a prev_declared_variable_name_token + * whenever it comes across it. + * When we finish parsing the function the variable name + * symbol table is cleared of all entries, and the function + * name is inserted into the library element symbol table. This + * means that from then onwards flex will return a + * derived_function_name_token whenever it comes across the + * function name. + * + * In order to insert the function name into the variable_name + * symbol table BEFORE the function body gets parsed, we + * need the parser to reduce a construct that contains the + * the function name. That is why we created this extra + * construct (function_name_declaration), i.e. to force + * the parser to reduce it, before parsing the function body! + */ +function_name_declaration: + FUNCTION derived_function_name + {$$ = $2; + /* the function name functions as a + * variable within the function itself! + * + * Remember that the variable_name_symtable + * is cleared once the end of the function + * is parsed. + */ + variable_name_symtable.insert($2, prev_declared_variable_name_token); + } +/* ERROR_CHECK_BEGIN */ +| FUNCTION error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no function name defined in function declaration.");} + else {print_err_msg(locf(@2), locl(@2), "invalid function name in function declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +/* intermediate helper symbol for function_declaration */ +io_OR_function_var_declarations_list: + io_var_declarations + {$$ = new var_declarations_list_c(locloc(@1));$$->add_element($1);} +| function_var_decls + {$$ = new var_declarations_list_c(locloc(@1));$$->add_element($1);} +| io_OR_function_var_declarations_list io_var_declarations + {$$ = $1; $$->add_element($2);} +| io_OR_function_var_declarations_list function_var_decls + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| io_OR_function_var_declarations_list retentive_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected retentive variable(s) declaration in function declaration."); yynerrs++;} +| io_OR_function_var_declarations_list located_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected located variable(s) declaration in function declaration."); yynerrs++;} +| io_OR_function_var_declarations_list external_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected external variable(s) declaration in function declaration."); yynerrs++;} +| io_OR_function_var_declarations_list global_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected global variable(s) declaration in function declaration."); yynerrs++;} +| io_OR_function_var_declarations_list incompl_located_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected incomplete located variable(s) declaration in function declaration."); yynerrs++;} +| io_OR_function_var_declarations_list temp_var_decls + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected temporary located variable(s) declaration in function declaration."); yynerrs++;} +| io_OR_function_var_declarations_list non_retentive_var_decls + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected non-retentive variable(s) declaration in function declaration."); yynerrs++;} +/*| io_OR_function_var_declarations_list access_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected access variable(s) declaration in function declaration."); yynerrs++;}*/ +| io_OR_function_var_declarations_list instance_specific_initializations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected instance specific initialization(s) in function declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +io_var_declarations: + input_declarations +| output_declarations +| input_output_declarations +; + + +function_var_decls: + VAR CONSTANT var2_init_decl_list END_VAR + {$$ = new function_var_decls_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} +| VAR var2_init_decl_list END_VAR + {$$ = new function_var_decls_c(NULL, $2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR error var2_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR' in function variable(s) declaration."); yyerrok;} +| VAR CONSTANT error var2_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant function variable(s) declaration."); yyerrok;} +| VAR var2_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed function variable(s) declaration."); yyerrok;} +| VAR CONSTANT var2_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant function variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* intermediate helper symbol for function_var_decls */ +var2_init_decl_list: + var2_init_decl ';' + {$$ = new var2_init_decl_list_c(locloc(@$)); $$->add_element($1);} +| var2_init_decl_list var2_init_decl ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| var2_init_decl error + {$$ = new var2_init_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of function variable(s) declaration."); yyerrok;} +| var2_init_decl_list var2_init_decl error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of function variable(s) declaration."); yyerrok;} +| var2_init_decl_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid function variable(s) declaration."); yyerrok;} +| var2_init_decl_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after function variable(s) declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +function_body: + statement_list {$$ = $1;} /* if we leave it for the default action we get a type clash! */ +| instruction_list {$$ = $1;} /* if we leave it for the default action we get a type clash! */ +/* +| ladder_diagram +| function_block_diagram +*/ +; + + +var2_init_decl: + var1_init_decl +| array_var_init_decl +| structured_var_init_decl +| string_var_declaration +; + + + +/*****************************/ +/* B 1.5.2 - Function Blocks */ +/*****************************/ +function_block_type_name: + prev_declared_derived_function_block_name +| standard_function_block_name +; + + +standard_function_block_name: standard_function_block_name_token {$$ = new identifier_c($1, locloc(@$));}; + +derived_function_block_name: identifier; + + +function_block_declaration: + FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK + {$$ = new function_block_declaration_c($2, $3, $4, locloc(@$)); + add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ + library_element_symtable.insert($2, prev_declared_derived_function_block_name_token); + /* Clear the variable_name_symtable. Since + * we have finished parsing the function block, + * the variable names are now out of scope, so + * are no longer valid! + */ + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + } +/* ERROR_CHECK_BEGIN */ +| FUNCTION_BLOCK io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in function block declaration."); yynerrs++;} +| FUNCTION_BLOCK error io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name in function block declaration."); yyerrok;} +| FUNCTION_BLOCK derived_function_block_name function_block_body END_FUNCTION_BLOCK + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared in function declaration."); yynerrs++;} +| FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list END_FUNCTION_BLOCK + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no body defined in function block declaration."); yynerrs++;} +| FUNCTION_BLOCK derived_function_block_name END_FUNCTION_BLOCK + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared and body defined in function block declaration."); yynerrs++;} +| FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "no variable(s) declared and body defined in function block declaration."); yynerrs++;} +| FUNCTION_BLOCK error END_FUNCTION_BLOCK + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in function block declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + +/* intermediate helper symbol for function_declaration */ +/* { io_var_declarations | other_var_declarations } */ +/* + * NOTE: we re-use the var_declarations_list_c + */ +io_OR_other_var_declarations_list: + io_var_declarations + {$$ = new var_declarations_list_c(locloc(@$));$$->add_element($1);} +| other_var_declarations + {$$ = new var_declarations_list_c(locloc(@$));$$->add_element($1);} +| io_OR_other_var_declarations_list io_var_declarations + {$$ = $1; $$->add_element($2);} +| io_OR_other_var_declarations_list other_var_declarations + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| io_OR_other_var_declarations_list located_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected located variable(s) declaration in function block declaration."); yynerrs++;} +| io_OR_other_var_declarations_list global_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected global variable(s) declaration in function block declaration."); yynerrs++;} +/*| io_OR_other_var_declarations_list access_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected access variable(s) declaration in function block declaration."); yynerrs++;}*/ +| io_OR_other_var_declarations_list instance_specific_initializations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected instance specific initialization(s) in function block declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +/* NOTE: + * The IEC specification gives the following definition: + * other_var_declarations ::= + * external_var_declarations + * | var_declarations + * | retentive_var_declarations + * | non_retentive_var_declarations + * | temp_var_decls + * | incompl_located_var_declarations + * + * Nvertheless, the symbol non_retentive_var_declarations + * is not defined in the spec. This seems to me (Mario) + * to be a typo, so non_retentive_var_declarations + * has been replaced with non_retentive_var_decls + * in the following rule! + */ +other_var_declarations: + temp_var_decls +| non_retentive_var_decls +| external_var_declarations +| var_declarations +| retentive_var_declarations +| incompl_located_var_declarations +; + + +temp_var_decls: + VAR_TEMP temp_var_decls_list END_VAR + {$$ = new temp_var_decls_c($2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR_TEMP END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in temporary variable(s) declaration."); yynerrs++;} +| VAR_TEMP temp_var_decls_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "unclosed temporary variable(s) declaration."); yyerrok;} +| VAR_TEMP error temp_var_decls_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_TEMP' in function variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* intermediate helper symbol for temp_var_decls */ +temp_var_decls_list: + temp_var_decl ';' + {$$ = new temp_var_decls_list_c(locloc(@$)); $$->add_element($1);} +| temp_var_decls_list temp_var_decl ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new temp_var_decls_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid temporary variable(s) declaration."); yyerrok;} +| temp_var_decl error + {$$ = new temp_var_decls_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of temporary variable(s) declaration."); yyerrok;} +| temp_var_decls_list temp_var_decl error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of temporary variable(s) declaration."); yyerrok;} +| temp_var_decls_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid temporary variable(s) declaration."); yyerrok;} +| temp_var_decls_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after temporary variable(s) declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +non_retentive_var_decls: + VAR NON_RETAIN var_init_decl_list END_VAR + {$$ = new non_retentive_var_decls_c($3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR NON_RETAIN var_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unclosed non-retentive temporary variable(s) declaration."); yyerrok;} +| VAR NON_RETAIN error var_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive temporary variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + +function_block_body: + statement_list {$$ = $1;} +| instruction_list {$$ = $1;} +| sequential_function_chart {$$ = $1;} +/* +| ladder_diagram +| function_block_diagram +| +*/ +; + + + + +/**********************/ +/* B 1.5.3 - Programs */ +/**********************/ +program_type_name: identifier; + + +program_declaration: + PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM + {$$ = new program_declaration_c($2, $3, $4, locloc(@$)); + library_element_symtable.insert($2, prev_declared_program_type_name_token); + /* Clear the variable_name_symtable. Since + * we have finished parsing the program declaration, + * the variable names are now out of scope, so + * are no longer valid! + */ + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + } +/* ERROR_CHECK_BEGIN */ +| PROGRAM program_var_declarations_list function_block_body END_PROGRAM + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no program name defined in program declaration.");} +| PROGRAM error program_var_declarations_list function_block_body END_PROGRAM + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid program name in program declaration."); yyerrok;} +| PROGRAM program_type_name function_block_body END_PROGRAM + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared in program declaration."); yynerrs++;} +| PROGRAM program_type_name program_var_declarations_list END_PROGRAM + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no body defined in program declaration."); yynerrs++;} +| PROGRAM program_type_name END_PROGRAM + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared and body defined in program declaration."); yynerrs++;} +| PROGRAM program_type_name program_var_declarations_list function_block_body END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed program declaration."); yynerrs++;} +| PROGRAM error END_PROGRAM + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in program declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* helper symbol for program_declaration */ +/* + * NOTE: we re-use the var_declarations_list_c + */ +program_var_declarations_list: + io_var_declarations + {$$ = new var_declarations_list_c(locloc(@$)); $$->add_element($1);} +| other_var_declarations + {$$ = new var_declarations_list_c(locloc(@$)); $$->add_element($1);} +| located_var_declarations + {$$ = new var_declarations_list_c(locloc(@$)); $$->add_element($1);} +| program_var_declarations_list io_var_declarations + {$$ = $1; $$->add_element($2);} +| program_var_declarations_list other_var_declarations + {$$ = $1; $$->add_element($2);} +| program_var_declarations_list located_var_declarations + {$$ = $1; $$->add_element($2);} +/* +| program_var_declarations_list program_access_decls + {$$ = $1; $$->add_element($2);} +*/ +/* ERROR_CHECK_BEGIN */ +| program_var_declarations_list global_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected global variable(s) declaration in function block declaration."); yynerrs++;} +/*| program_var_declarations_list access_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected access variable(s) declaration in function block declaration."); yynerrs++;}*/ +| program_var_declarations_list instance_specific_initializations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected instance specific initialization(s) in function block declaration."); yynerrs++; + } +/* ERROR_CHECK_END */ +; + + +/* TODO ... */ +/* +program_access_decls: + VAR_ACCESS program_access_decl_list END_VAR +; +*/ + +/* helper symbol for program_access_decls */ +/* +program_access_decl_list: + program_access_decl ';' +| program_access_decl_list program_access_decl ';' +; +*/ + +/* +program_access_decl: + access_name ':' symbolic_variable ':' non_generic_type_name +| access_name ':' symbolic_variable ':' non_generic_type_name direction +; +*/ + + + +/********************************************/ +/* B 1.6 Sequential Function Chart elements * +/********************************************/ + +sequential_function_chart: + sfc_network + {$$ = new sequential_function_chart_c(locloc(@$)); $$->add_element($1);} +| sequential_function_chart sfc_network + {$$ = $1; $$->add_element($2);} +; + +sfc_network: + initial_step + {$$ = new sfc_network_c(locloc(@$)); $$->add_element($1);} +| sfc_network step + {$$ = $1; $$->add_element($2);} +| sfc_network transition + {$$ = $1; $$->add_element($2);} +| sfc_network action + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| sfc_network error + {$$ = $1; print_err_msg(locl(@1), locf(@2), "unexpected token after SFC network in sequencial function chart."); yyerrok;} +/* ERROR_CHECK_END */ +; + +initial_step: + INITIAL_STEP step_name ':' action_association_list END_STEP +// INITIAL_STEP identifier ':' action_association_list END_STEP + {$$ = new initial_step_c($2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| INITIAL_STEP ':' action_association_list END_STEP + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "no step name defined in initial step declaration."); yynerrs++;} +| INITIAL_STEP error ':' action_association_list END_STEP + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid step name defined in initial step declaration."); yyerrok;} +| INITIAL_STEP step_name action_association_list END_STEP + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':' missing after step name in initial step declaration."); yynerrs++;} +| INITIAL_STEP step_name ':' error END_STEP + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid action association list in initial step declaration."); yyerrok;} +| INITIAL_STEP step_name ':' action_association_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed initial step declaration."); yynerrs++;} +| INITIAL_STEP error END_STEP + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in initial step declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +step: + STEP step_name ':' action_association_list END_STEP +// STEP identifier ':' action_association_list END_STEP + {$$ = new step_c($2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| STEP ':' action_association_list END_STEP + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no step name defined in step declaration."); yynerrs++;} +| STEP error ':' action_association_list END_STEP + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid step name defined in step declaration."); yyerrok;} +| STEP step_name action_association_list END_STEP + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':' missing after step name in step declaration."); yynerrs++;} +| STEP step_name ':' error END_STEP + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid action association list in step declaration."); yyerrok;} +| STEP step_name ':' action_association_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@3), "invalid action association list in step declaration."); yynerrs++;} +| STEP error END_STEP + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in step declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for: + * - initial_step + * - step + */ +action_association_list: + /* empty */ + {$$ = new action_association_list_c(locloc(@$));} +| action_association_list action_association ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| action_association_list action_association error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of action association declaration."); yyerrok;} +| action_association_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after action association declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +// step_name: identifier; +step_name: any_identifier; + +action_association: + action_name '(' {cmd_goto_sfc_qualifier_state();} action_qualifier {cmd_pop_state();} indicator_name_list ')' + {$$ = new action_association_c($1, $4, $6, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +/*| action_name '(' error ')' + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid qualifier defined in action association."); yyerrok;}*/ +/* ERROR_CHECK_END */ +; + +/* helper symbol for action_association */ +indicator_name_list: + /* empty */ + {$$ = new indicator_name_list_c(locloc(@$));} +| indicator_name_list ',' indicator_name + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| indicator_name_list indicator_name + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing at end of action association declaration."); yynerrs++;} +| indicator_name_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no indicator defined in indicator list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid indicator in indicator list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +// action_name: identifier; +action_name: any_identifier; + +action_qualifier: + /* empty */ + {$$ = NULL;} +| qualifier + {$$ = new action_qualifier_c($1, NULL, locloc(@$));} +| timed_qualifier ',' action_time + {$$ = new action_qualifier_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| timed_qualifier action_time + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "',' missing between timed qualifier and action time in action qualifier."); yynerrs++;} +| timed_qualifier ',' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no action time defined in action qualifier.");} + else {print_err_msg(locf(@3), locl(@3), "invalid action time in action qualifier."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +qualifier: + N {$$ = new qualifier_c(strdup("N"), locloc(@$));} +| R {$$ = new qualifier_c(strdup("R"), locloc(@$));} +| S {$$ = new qualifier_c(strdup("S"), locloc(@$));} +| P {$$ = new qualifier_c(strdup("P"), locloc(@$));} +; + +timed_qualifier: + L {$$ = new timed_qualifier_c(strdup("L"), locloc(@$));} +| D {$$ = new timed_qualifier_c(strdup("D"), locloc(@$));} +| SD {$$ = new timed_qualifier_c(strdup("SD"), locloc(@$));} +| DS {$$ = new timed_qualifier_c(strdup("DS"), locloc(@$));} +| SL {$$ = new timed_qualifier_c(strdup("SL"), locloc(@$));} +; + +action_time: + duration +| variable +; + +indicator_name: variable; + +// transition_name: identifier; +transition_name: any_identifier; + + +steps: + step_name + {$$ = new steps_c($1, NULL, locloc(@$));} +| '(' step_name_list ')' + {$$ = new steps_c(NULL, $2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| '(' step_name_list error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "expecting ')' at the end of step list in transition declaration."); yyerrok;} +| '(' error ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid step list in transition declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +step_name_list: + step_name ',' step_name + {$$ = new step_name_list_c(locloc(@$)); $$->add_element($1); $$->add_element($3);} +| step_name_list ',' step_name + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| step_name_list step_name + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in step list."); yynerrs++;} +| step_name_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no step name defined in step list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid step name in step list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +/* NOTE: flex will automatically pop() out of body_state to previous state. + * We do not need to give a command from bison to return to previous flex state, + * after forcing flex to go to body_state. + */ +transition: + TRANSITION transition_priority + FROM steps TO steps + {cmd_goto_body_state();} transition_condition + END_TRANSITION + {$$ = new transition_c(NULL, $2, $4, $6, $8, locloc(@$));} +//| TRANSITION identifier FROM steps TO steps ... +| TRANSITION transition_name transition_priority + FROM steps TO steps + {cmd_goto_body_state();} transition_condition + END_TRANSITION + {$$ = new transition_c($2, $3, $5, $7, $9, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| TRANSITION error transition_priority FROM steps TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid transition name defined in transition declaration."); yyerrok;} +| TRANSITION transition_name error FROM steps TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid transition priority defined in transition declaration."); yyerrok;} +| TRANSITION transition_priority FROM TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no origin step(s) defined in transition declaration."); yynerrs++;} +| TRANSITION transition_name transition_priority FROM TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no origin step(s) defined in transition declaration."); yynerrs++;} +| TRANSITION transition_priority FROM error TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid origin step(s) defined in transition declaration."); yyerrok;} +| TRANSITION transition_name transition_priority FROM error TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locf(@5), locl(@5), "invalid origin step(s) defined in transition declaration."); yyerrok;} +| TRANSITION transition_priority FROM steps steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "'TO' missing between origin step(s) and destination step(s) in transition declaration."); yynerrs++;} +| TRANSITION transition_name transition_priority FROM steps steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@5), locf(@6), "'TO' missing between origin step(s) and destination step(s) in transition declaration."); yynerrs++;} +| TRANSITION transition_priority FROM steps TO {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@5), locf(@7), "no destination step(s) defined in transition declaration."); yynerrs++;} +| TRANSITION transition_name transition_priority FROM steps TO {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@6), locf(@8), "no destination step(s) defined in transition declaration."); yynerrs++;} +| TRANSITION transition_priority FROM steps TO error {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid destination step(s) defined in transition declaration."); yyerrok;} +| TRANSITION transition_name transition_priority FROM steps TO error {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locf(@7), locl(@7), "invalid destination step(s) defined in transition declaration."); yyerrok;} +| TRANSITION transition_priority {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@2), locf(@4), "no origin and destination step(s) defined in transition declaration."); yynerrs++;} +| TRANSITION transition_name transition_priority {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@3), locf(@5), "no origin and destination step(s) defined in transition declaration."); yynerrs++;} +/*| TRANSITION transition_priority FROM steps TO steps {cmd_goto_body_state();} transition_condition error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@6), "unclosed transition declaration."); yyerrok;} +| TRANSITION transition_name transition_priority FROM steps TO steps {cmd_goto_body_state();} transition_condition error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@7), "unclosed transition declaration."); yyerrok;}*/ +| TRANSITION error END_TRANSITION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in transition declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +transition_priority: + /* empty */ + {$$ = NULL;} +| '(' {cmd_goto_sfc_priority_state();} PRIORITY {cmd_pop_state();} ASSIGN integer ')' + {$$ = $6;} +/* ERROR_CHECK_BEGIN +| '(' ASSIGN integer ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'PRIORITY' missing between '(' and ':=' in transition declaration with priority."); yynerrs++;} +| '(' error ASSIGN integer ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "expecting 'PRIORITY' between '(' and ':=' in transition declaration with priority."); yyerrok;} + ERROR_CHECK_END */ +; + + +transition_condition: + ':' eol_list simple_instr_list + {$$ = new transition_condition_c($3, NULL, locloc(@$));} +| ASSIGN expression ';' + {$$ = new transition_condition_c(NULL, $2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| eol_list simple_instr_list + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing before IL condition in transition declaration."); yynerrs++;} +| ':' eol_list error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no instructions defined in IL condition of transition declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid instructions in IL condition of transition declaration."); yyclearin;} + yyerrok; + } +| ASSIGN ';' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no expression defined in ST condition of transition declaration."); yynerrs++;} +| ASSIGN error ';' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid expression defined in ST condition of transition declaration."); yyerrok;} +| ASSIGN expression error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "expecting ';' after expression defined in ST condition of transition declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + +action: +// ACTION identifier ':' ... + ACTION action_name {cmd_goto_body_state();} action_body END_ACTION + {$$ = new action_c($2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| ACTION {cmd_goto_body_state();} action_body END_ACTION + {$$ = NULL; print_err_msg(locl(@1), locf(@3), "no action name defined in action declaration."); yynerrs++;} +| ACTION error {cmd_goto_body_state();} action_body END_ACTION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid action name defined in action declaration."); yyerrok;} +| ACTION action_name {cmd_goto_body_state();} function_block_body END_ACTION + {$$ = NULL; print_err_msg(locl(@2), locf(@4), "':' missing after action name in action declaration."); yynerrs++;} +/*| ACTION action_name {cmd_goto_body_state();} action_body END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed action declaration."); yyerrok;}*/ +| ACTION error END_ACTION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in action declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +action_body: + ':' function_block_body + {$$ = $2;} +/* ERROR_CHECK_BEGIN */ +| ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no body defined in action declaration.");} + else {print_err_msg(locf(@2), locl(@2), "invalid body defined in action declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +/********************************/ +/* B 1.7 Configuration elements */ +/********************************/ +/* NOTE: + * It is not clear from reading the specification to which namespace + * the names of resources, tasks and programs belong to. + * + * The following syntax assumes that resource and program names belong to the + * same namespace as the variables defined within + * the resource/configuration (i.e. VAR_GLOBAL). + * Task names belong to a namespace all of their own, since they don't + * produce conflicts in the syntax parser, so we might just as well + * leave them be! ;-) + * The above decision was made taking into + * account that inside a VAR_CONFIG declaration global variables + * may be referenced starting off from the resource name as: + * resource_name.program_name.variable_name + * Notice how resource names and program names are used in a very similar + * manner as are variable names. + * Using a single namespace for all the above mentioned names + * also makes it easier to write the syntax parser!! ;-) Using a private + * namespace for each of the name types (resource names, program names, + * global varaiable names), i.e. letting the names be re-used across + * each of the groups (resource, program, global variables), produces + * reduce/reduce conflicts in the syntax parser. Actually, it is only + * the resource names that need to be distinguished into a + * prev_declared_resource_name so as not to conflict with [gloabl] variable + * names in the 'data' construct. + * The program names are only tracked to make sure that two programs do not + * get the same name. + * + * Using a single namespace does have the drawback that the user will + * not be able to re-use names for resources or programs if these + * have already been used to name a variable! + * + * If it ever becomes necessary to change this interpretation of + * the syntax, then this section of the syntax parser must be updated! + */ +prev_declared_global_var_name: prev_declared_global_var_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_resource_name: prev_declared_resource_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_program_name: prev_declared_program_name_token {$$ = new identifier_c($1, locloc(@$));}; +// prev_declared_task_name: prev_declared_task_name_token {$$ = new identifier_c($1, locloc(@$));}; + + + + + + +configuration_name: identifier; + +/* NOTE: The specification states that valid resource type names + * are implementation defined, i.e. each implementaion will define + * what resource types it supports. + * We are implementing this syntax parser to be used by any + * implementation, so at the moment we accept any identifier + * as a resource type name. + * This implementation should probably be changed in the future. We + * should probably have a resource_type_name_token, and let the + * implementation load the global symbol library with the + * accepted resource type names before parsing the code. + * + */ +resource_type_name: any_identifier; + +configuration_declaration: + CONFIGURATION configuration_name + optional_global_var_declarations + single_resource_declaration + {variable_name_symtable.pop(); + direct_variable_symtable.pop();} + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = new configuration_declaration_c($2, $3, $4, $6, $7, locloc(@$)); + library_element_symtable.insert($2, prev_declared_configuration_name_token); + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + } +| CONFIGURATION configuration_name + optional_global_var_declarations + resource_declaration_list + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = new configuration_declaration_c($2, $3, $4, $5, $6, locloc(@$)); + library_element_symtable.insert($2, prev_declared_configuration_name_token); + variable_name_symtable.pop(); + direct_variable_symtable.pop(); +} +/* ERROR_CHECK_BEGIN */ +| CONFIGURATION + optional_global_var_declarations + single_resource_declaration + {variable_name_symtable.pop(); + direct_variable_symtable.pop();} + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no configuration name defined in configuration declaration."); yynerrs++;} +| CONFIGURATION + optional_global_var_declarations + resource_declaration_list + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no configuration name defined in configuration declaration."); yynerrs++;} +| CONFIGURATION error + optional_global_var_declarations + single_resource_declaration + {variable_name_symtable.pop(); + direct_variable_symtable.pop();} + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid configuration name defined in configuration declaration."); yyerrok;} +| CONFIGURATION error + optional_global_var_declarations + resource_declaration_list + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid configuration name defined in configuration declaration."); yyerrok;} +| CONFIGURATION configuration_name + optional_global_var_declarations + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no resource(s) defined in configuration declaration."); yynerrs++;} +| CONFIGURATION configuration_name + optional_global_var_declarations + error + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid resource(s) defined in configuration declaration."); yyerrok;} +/*| CONFIGURATION configuration_name + optional_global_var_declarations + single_resource_declaration + {variable_name_symtable.pop(); + direct_variable_symtable.pop();} + optional_access_declarations + optional_instance_specific_initializations + END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed configuration declaration."); yyerrok;}*/ +| CONFIGURATION configuration_name + optional_global_var_declarations + resource_declaration_list + optional_access_declarations + optional_instance_specific_initializations + END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed configuration declaration."); yyerrok;} +| CONFIGURATION error END_CONFIGURATION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in configuration declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +// helper symbol for +// - configuration_declaration +// - resource_declaration +// +optional_global_var_declarations: + // empty + {$$ = NULL;} +| global_var_declarations +; + + +// helper symbol for configuration_declaration // +optional_access_declarations: + // empty + {$$ = NULL;} +//| access_declarations +; + +// helper symbol for configuration_declaration // +optional_instance_specific_initializations: + // empty + {$$ = NULL;} +| instance_specific_initializations +; + +// helper symbol for configuration_declaration // +resource_declaration_list: + resource_declaration + {$$ = new resource_declaration_list_c(locloc(@$)); $$->add_element($1);} +| resource_declaration_list resource_declaration + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| resource_declaration_list error + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected token after resource declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +resource_declaration: + RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} resource_name ON resource_type_name + optional_global_var_declarations + single_resource_declaration + END_RESOURCE + {$$ = new resource_declaration_c($3, $5, $6, $7, locloc(@$)); + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + variable_name_symtable.insert($3, prev_declared_resource_name_token); + } +/* ERROR_CHECK_BEGIN */ +| RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} ON resource_type_name + optional_global_var_declarations + single_resource_declaration + END_RESOURCE + {$$ = NULL; print_err_msg(locl(@1), locf(@3), "no resource name defined in resource declaration."); yynerrs++;} +/*| RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} resource_name ON resource_type_name + optional_global_var_declarations + single_resource_declaration + END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@5), "unclosed resource declaration."); yyerrok;}*/ +| RESOURCE error END_RESOURCE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in resource declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +single_resource_declaration: + task_configuration_list program_configuration_list + {$$ = new single_resource_declaration_c($1, $2, locloc(@$));} +; + + +// helper symbol for single_resource_declaration // +task_configuration_list: + // empty + {$$ = new task_configuration_list_c(locloc(@$));} +| task_configuration_list task_configuration ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| task_configuration_list task_configuration error + {$$ = $1; print_err_msg(locl(@1), locf(@2), "';' missing at the end of task configuration in resource declaration."); yyerrok;} +| task_configuration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after task configuration in resource declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +// helper symbol for single_resource_declaration // +program_configuration_list: + program_configuration ';' + {$$ = new program_configuration_list_c(locloc(@$)); $$->add_element($1);} +| program_configuration_list program_configuration ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| program_configuration error + {$$ = new program_configuration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at the end of program configuration in resource declaration."); yyerrok;} +| program_configuration_list program_configuration error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of program configuration in resource declaration."); yyerrok;} +| program_configuration_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid program configuration in resource declaration."); yyerrok;} +| program_configuration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after program configuration in resource declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +resource_name: identifier; + +/* +access_declarations: + VAR_ACCESS access_declaration_list END_VAR + {$$ = NULL;} +// ERROR_CHECK_BEGIN // +| VAR_ACCESS END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in access variable(s) declaration."); yynerrs++;} +| VAR_ACCESS error access_declaration_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_ACCESS' in access variable(s) declaration."); yyerrok;} +| VAR_ACCESS access_declaration_list error END_VAR + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed access variable(s) declaration."); yyerrok;} +| VAR_ACCESS error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in access variable(s) declaration."); yyerrok;} +// ERROR_CHECK_END // +; + +// helper symbol for access_declarations // +access_declaration_list: + access_declaration ';' +| access_declaration_list access_declaration ';' +// ERROR_CHECK_BEGIN // +| error ';' + {$$ = // create a new list //; + print_err_msg(locf(@1), locl(@1), "invalid access variable declaration."); yyerrok;} +| access_declaration error + {$$ = // create a new list //; + print_err_msg(locl(@1), locf(@2), "';' missing at the end of access variable declaration."); yyerrok;} +| access_declaration_list access_declaration error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of access variable declaration."); yyerrok;} +| access_declaration_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid access variable declaration."); yyerrok;} +| access_declaration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after access variable declaration."); yynerrs++;} +// ERROR_CHECK_END // +; + + +access_declaration: + access_name ':' access_path ':' non_generic_type_name +| access_name ':' access_path ':' non_generic_type_name direction +; + + +access_path: + prev_declared_direct_variable +| prev_declared_resource_name '.' prev_declared_direct_variable +| any_fb_name_list symbolic_variable +| prev_declared_resource_name '.' any_fb_name_list symbolic_variable +| prev_declared_program_name '.' any_fb_name_list symbolic_variable +| prev_declared_resource_name '.' prev_declared_program_name '.' any_fb_name_list symbolic_variable +; +*/ + +// helper symbol for +// - access_path +// - instance_specific_init +// +/* NOTE: The fb_name_list refers to funtion block variables + * that have been declared in a scope outside the one we are + * currently parsing, so we must accept them to be any_identifier! + * + * Beware that other locations of this syntax parser also require + * a fb_name_list. In those locations the function blocks are being declared, + * so only currently un-used identifiers (i.e. identifier) may be accepted. + * + * In order to distinguish the two, here we use any_fb_name_list, while + * in the the locations we simply use fb_name_list! + */ +any_fb_name_list: + // empty + {$$ = new any_fb_name_list_c(locloc(@$));} +//| fb_name_list fb_name '.' +| any_fb_name_list any_identifier '.' + {$$ = $1; $$->add_element($2);} +; + + + +global_var_reference: +// [resource_name '.'] global_var_name ['.' structure_element_name] // + prev_declared_global_var_name + {$$ = new global_var_reference_c(NULL, $1, NULL, locloc(@$));} +| prev_declared_global_var_name '.' structure_element_name + {$$ = new global_var_reference_c(NULL, $1, $3, locloc(@$));} +| prev_declared_resource_name '.' prev_declared_global_var_name + {$$ = new global_var_reference_c($1, $3, NULL, locloc(@$));} +| prev_declared_resource_name '.' prev_declared_global_var_name '.' structure_element_name + {$$ = new global_var_reference_c($1, $3, $5, locloc(@$));} +; + + +//access_name: identifier; + + +program_output_reference: +/* NOTE: + * program_output_reference is merely used within data_source. + * data_source is merely used within task_initialization + * task_initialization appears in a configuration declaration + * _before_ the programs are declared, so we cannot use + * prev_declared_program_name, as what might seem correct at first. + * + * The semantic checker must later check whether the identifier + * used really refers to a program declared after the task + * initialization! + */ +// prev_declared_program_name '.' symbolic_variable + program_name '.' symbolic_variable + {$$ = new program_output_reference_c($1, $3, locloc(@$));} +; + +program_name: identifier; + +/* +direction: + READ_WRITE + {$$ = NULL;} +| READ_ONLY + {$$ = NULL;} +; +*/ + +task_configuration: + TASK task_name task_initialization + {$$ = new task_configuration_c($2, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| TASK task_initialization + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no task name defined in task declaration."); yynerrs++;} +| TASK error task_initialization + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid task name defined in task declaration."); yyerrok;} +| TASK task_name error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no task initialization defined in task declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid task initialization in task declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* NOTE: The specification does not mention the namespace to which task names + * should belong to. Unlike resource and program names, for the moment we + * let the task names belong to their own private namespace, as they do not + * produce any conflicts in the syntax parser. + * If in the future our interpretation of the spec. turns out to be incorrect, + * the definition of task_name may have to be changed! + */ +task_name: any_identifier; + + +task_initialization: +// '(' [SINGLE ASSIGN data_source ','] [INTERVAL ASSIGN data_source ','] PRIORITY ASSIGN integer ')' // + '(' {cmd_goto_task_init_state();} task_initialization_single task_initialization_interval task_initialization_priority ')' + {$$ = new task_initialization_c($3, $4, $5, locloc(@$));} +; + + +task_initialization_single: +// [SINGLE ASSIGN data_source ','] + /* empty */ + {$$ = NULL;} +| SINGLE ASSIGN {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} + {$$ = $4;} +/* ERROR_CHECK_BEGIN */ +| SINGLE {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} + {$$ = NULL; print_err_msg(locl(@1), locf(@3), "':=' missing after 'SINGLE' in task initialization."); yynerrs++;} +| SINGLE ASSIGN {cmd_pop_state();} ',' {cmd_goto_task_init_state();} + {$$ = NULL; print_err_msg(locl(@2), locf(@4), "no data source defined in 'SINGLE' statement of task initialization."); yynerrs++;} +| SINGLE ASSIGN {cmd_pop_state();} error ',' {cmd_goto_task_init_state();} + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid data source defined in 'SINGLE' statement of task initialization."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +task_initialization_interval: +// [INTERVAL ASSIGN data_source ','] + /* empty */ + {$$ = NULL;} +| INTERVAL ASSIGN {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} + {$$ = $4;} +/* ERROR_CHECK_BEGIN */ +| INTERVAL {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} + {$$ = NULL; print_err_msg(locl(@1), locf(@3), "':=' missing after 'INTERVAL' in task initialization.");} +| INTERVAL ASSIGN {cmd_pop_state();} ',' {cmd_goto_task_init_state();} + {$$ = NULL; print_err_msg(locl(@2), locf(@4), "no data source defined in 'INTERVAL' statement of task initialization."); yynerrs++;} +| INTERVAL ASSIGN {cmd_pop_state();} error ',' {cmd_goto_task_init_state();} + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid data source defined in 'INTERVAL' statement of task initialization."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + +task_initialization_priority: +// PRIORITY ASSIGN integer + PRIORITY ASSIGN {cmd_pop_state();} integer + {$$ = $4;} +/* ERROR_CHECK_BEGIN */ +| PRIORITY {cmd_pop_state();} integer + {$$ = NULL; print_err_msg(locl(@1), locf(@3), "':=' missing after 'PRIORITY' in task initialization."); yynerrs++;} +| PRIORITY ASSIGN {cmd_pop_state();} error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@4), "no priority number defined in 'PRIORITY' statement of task initialization.");} + else {print_err_msg(locf(@4), locl(@4), "invalid priority number in 'PRIORITY' statement of task initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +data_source: + constant +| global_var_reference +| program_output_reference +| prev_declared_direct_variable +; + +program_configuration: +// PROGRAM [RETAIN | NON_RETAIN] program_name [WITH task_name] ':' program_type_name ['(' prog_conf_elements ')'] // + PROGRAM program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = new program_configuration_c(NULL, $2, $3, $5, $6, locloc(@$)); + variable_name_symtable.insert($2, prev_declared_program_name_token); + } +| PROGRAM RETAIN program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = new program_configuration_c(new retain_option_c(locloc(@2)), $3, $4, $6, $7, locloc(@$)); + variable_name_symtable.insert($3, prev_declared_program_name_token); + } +| PROGRAM NON_RETAIN program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = new program_configuration_c(new non_retain_option_c(locloc(@2)), $3, $4, $6, $7, locloc(@$)); + variable_name_symtable.insert($3, prev_declared_program_name_token); + } +/* ERROR_CHECK_BEGIN */ +| PROGRAM program_name optional_task_name ':' identifier optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@5), locl(@5), "invalid program type name after ':' in program configuration."); yynerrs++;} +| PROGRAM RETAIN program_name optional_task_name ':' identifier optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid program type name after ':' in program configuration."); yynerrs++;} +| PROGRAM NON_RETAIN program_name optional_task_name ':' identifier optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid program type name after ':' in program configuration."); yynerrs++;} +| PROGRAM error program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'PROGRAM' in program configuration."); yyerrok;} +| PROGRAM RETAIN error program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive program configuration."); yyerrok;} +| PROGRAM NON_RETAIN error program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive program configuration."); yyerrok;} +| PROGRAM optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no program name defined in program configuration."); yynerrs++;} +| PROGRAM RETAIN optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no program name defined in retentive program configuration."); yynerrs++;} +| PROGRAM NON_RETAIN optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no program name defined in non-retentive program configuration."); yynerrs++;} +| PROGRAM error optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid program name defined in program configuration."); yyerrok;} +| PROGRAM RETAIN error optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid program name defined in retentive program configuration."); yyerrok;} +| PROGRAM NON_RETAIN error optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid program name defined in non-retentive program configuration."); yyerrok;} +| PROGRAM program_name optional_task_name prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "':' missing after program name or optional task name in program configuration."); yynerrs++;} +| PROGRAM RETAIN program_name optional_task_name prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':' missing after program name or optional task name in retentive program configuration."); yynerrs++;} +| PROGRAM NON_RETAIN program_name optional_task_name prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':' missing after program name or optional task name in non-retentive program configuration."); yynerrs++;} +| PROGRAM program_name optional_task_name ':' optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no program type defined in program configuration."); yynerrs++;} +| PROGRAM RETAIN program_name optional_task_name ':' optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@5), locf(@6), "no program type defined in retentive program configuration."); yynerrs++;} +| PROGRAM NON_RETAIN program_name optional_task_name ':' optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@5), locf(@6), "no program type defined in non-retentive program configuration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +// helper symbol for program_configuration // +optional_task_name: + // empty // + {$$ = NULL;} +| WITH task_name + {$$ = $2;} +/* ERROR_CHECK_BEGIN */ +| WITH error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no task name defined in optional task name of program configuration.");} + else {print_err_msg(locf(@2), locl(@2), "invalid task name in optional task name of program configuration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +// helper symbol for program_configuration // +optional_prog_conf_elements: + // empty // + {$$ = NULL;} +| '(' prog_conf_elements ')' + {$$ = $2;} +/* ERROR_CHECK_BEGIN */ +| '(' error ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid program configuration elements in program configuration."); yyerrok;} +| '(' prog_conf_elements error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of program configuration elements in program configuration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +prog_conf_elements: + prog_conf_element + {$$ = new prog_conf_elements_c(locloc(@$)); $$->add_element($1);} +| prog_conf_elements ',' prog_conf_element + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| prog_conf_elements prog_conf_element + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in program configuration elements list."); yynerrs++;} +| prog_conf_elements ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for program configuration element in program configuration list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for program configuration element in program configuration list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +prog_conf_element: + fb_task +| prog_cnxn +; + + +fb_task: + // fb_name WITH task_name +/* NOTE: The fb_name refers to funtion block variables + * that have been declared in a scope outside the one we are + * currently parsing, so we must accept them to be any_identifier! + */ + any_identifier WITH task_name + {$$ = new fb_task_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| any_identifier WITH error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no task name defined in function block configuration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid task name in function block configuration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +/* NOTE: + * The semantics of configuring a program are rather confusing, so here is + * my (Mario) understanding on the issue... + * + * A function/program may have as its input variables a simple variable + * (BYTE, WORD, etc...), an array (ARRAY [1 .. 3] OF BYTE, ...) , or a structure. + * Nevertheless, when calling this function from within a st or il language statement + * it is not possible to allocate a value to a single element of the array or structure + * typed input variable, as the accepted syntax is simply '(' variable_name ':=' variable ')' + * Notice how the variable_name does not include things such as 'a.elem1' or 'a[1]'! + * + * Nevertheless, when configuring a program from within a configuration, + * it becomes possible to allocate values to individual elements of the + * array or structured type input variable, as the syntax is now + * '(' symbolic_variable ':=' data_sink|prog_data_source ')' + * Notice how the symbolic_variable _does_ include things such as 'a.elem1' or 'a[1]'! + * + * Conclusion: Unlike other locations in the syntax where SENDTO appears, + * here it is not valid to replace symbolic_variable with any_identifier! + * Nevertheless, it is also not correct to leave symbolic_variable as it is, + * as we have defined it to only include previously declared variables, + * which is not the case in this situation. Here symbolic_variable is refering + * to variables that were defined within the scope of the program that is being + * called, and _not_ within the scope of the configuration that is calling the + * program, so the variables in question are not declared in the current scope! + * + * We therefore need to define a new symbolic_variable, that accepts any_identifier + * instead of previosuly declared variable names, to be used in the definition of + * prog_cnxn! + */ +prog_cnxn: + any_symbolic_variable ASSIGN prog_data_source + {$$ = new prog_cnxn_assign_c($1, $3, locloc(@$));} +| any_symbolic_variable SENDTO data_sink + {$$ = new prog_cnxn_sendto_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| any_symbolic_variable constant + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing between parameter and value in program configuration element."); yynerrs++;} +| any_symbolic_variable enumerated_value + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing between parameter and value in program configuration element."); yynerrs++;} +| any_symbolic_variable data_sink + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' or '=>' missing between parameter and variable in program configuration element."); yynerrs++;} +| any_symbolic_variable ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value or variable defined in program configuration assignment element.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value or variable in program configuration assignment element."); yyclearin;} + yyerrok; + } +| any_symbolic_variable SENDTO error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no variable defined in program configuration sendto element.");} + else {print_err_msg(locf(@3), locl(@3), "invalid variable in program configuration sendto element."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +prog_data_source: + constant +| enumerated_value +| global_var_reference +| prev_declared_direct_variable +; + +data_sink: + global_var_reference +| prev_declared_direct_variable +; + +instance_specific_initializations: + VAR_CONFIG instance_specific_init_list END_VAR + {$$ = new instance_specific_initializations_c($2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR_CONFIG END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in configuration variable(s) initialization."); yynerrs++;} +| VAR_CONFIG error instance_specific_init_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_CONFIG' in configuration variable(s) initialization."); yyerrok;} +| VAR_CONFIG instance_specific_init_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed configuration variable(s) initialization."); yyerrok;} +| VAR_CONFIG error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in configuration variable(s) initialization."); yyerrok;} +/* ERROR_CHECK_END */ +; + +// helper symbol for instance_specific_initializations // +instance_specific_init_list: + instance_specific_init ';' + {$$ = new instance_specific_init_list_c(locloc(@$)); $$->add_element($1);} +| instance_specific_init_list instance_specific_init ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new instance_specific_init_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid configuration variable initialization."); yyerrok;} +| instance_specific_init error + {$$ = new instance_specific_init_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at the end of configuration variable initialization."); yyerrok;} +| instance_specific_init_list instance_specific_init error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of configuration variable initialization."); yyerrok;} +| instance_specific_init_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid configuration variable initialization."); yyerrok;} +| instance_specific_init_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after configuration variable initialization."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +instance_specific_init: +// +// resource_name '.' program_name '.' {fb_name '.'} +// ((variable_name [location] ':' located_var_spec_init) | (fb_name ':' function_block_type_name ':=' structure_initialization)) +// +// prev_declared_resource_name '.' prev_declared_program_name '.' any_fb_name_list variable_name ':' located_var_spec_init +/* NOTE: variable_name has been changed to any_identifier (and not simply identifier) because the + * variables being referenced have been declared outside the scope currently being parsed! + */ +/* NOTE: program_name has not been changed to prev_declared_program_name because the + * programs being referenced have been declared outside the scope currently being parsed! + * The programs are only kept inside the scope of the resource in which they are defined. + */ + prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier ':' located_var_spec_init + {$$ = new instance_specific_init_c($1, $3, $5, $6, NULL, $8, locloc(@$));} +| prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier location ':' located_var_spec_init + {$$ = new instance_specific_init_c($1, $3, $5, $6, $7, $9, locloc(@$));} +| prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier ':' fb_initialization + {$5->add_element($6); $$ = new instance_specific_init_c($1, $3, $5, NULL, NULL, $8, locloc(@$));} +; + + +/* helper symbol for instance_specific_init */ +fb_initialization: + function_block_type_name ASSIGN structure_initialization + {$$ = new fb_initialization_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| function_block_type_name structure_initialization + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing between function block name and initialization in function block initialization."); yynerrs++;} +| function_block_type_name ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in function block initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid initial value in function block initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/***********************************/ +/* B 2.1 Instructions and Operands */ +/***********************************/ +/* helper symbol for many IL instructions, etc... */ +/* eat up any extra EOL tokens... */ + +eol_list: + EOL +| eol_list EOL +; + + + +instruction_list: + il_instruction + {$$ = new instruction_list_c(locloc(@$)); $$->add_element($1);} +| any_pragma eol_list + {$$ = new instruction_list_c(locloc(@$)); $$->add_element($1);} +| instruction_list il_instruction + {$$ = $1; $$->add_element($2);} +| instruction_list any_pragma + {$$ = $1; $$->add_element($2);} +; + + + +il_instruction: + il_incomplete_instruction eol_list + {$$ = new il_instruction_c(NULL, $1, locloc(@$));} +| label ':' il_incomplete_instruction eol_list + {$$ = new il_instruction_c($1, $3, locloc(@$));} +| label ':' eol_list + {$$ = new il_instruction_c($1, NULL, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| error eol_list + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid IL instruction."); yyerrok;} +| il_incomplete_instruction error + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing at the end of IL instruction."); yyerrok;} +| error ':' il_incomplete_instruction eol_list + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid label in IL instruction."); yyerrok;} +| label il_incomplete_instruction eol_list + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after label in IL instruction."); yynerrs++;} +| label ':' error eol_list + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid IL instruction."); yyerrok;} +| label ':' il_incomplete_instruction error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "EOL missing at the end of IL instruction."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* helper symbol for il_instruction */ +il_incomplete_instruction: + il_simple_operation +| il_expression +| il_jump_operation +| il_fb_call +| il_formal_funct_call +| il_return_operator +; + + +label: identifier; + + + +il_simple_operation: +// (il_simple_operator [il_operand]) | (function_name [il_operand_list]) + il_simple_operator + {$$ = new il_simple_operation_c($1, NULL, locloc(@$));} +/* + * Note: Bison is getting confused with the following rule, + * i.e. it is finding conflicts where there seemingly are really none. + * The rule was therefore replaced by the equivalent following + * two rules. + */ +/* +| il_simple_operator il_operand + {$$ = new il_simple_operation_c($1, $2, locloc(@$));} +*/ +| il_simple_operator_noclash il_operand + {$$ = new il_simple_operation_c($1, $2, locloc(@$));} +| il_simple_operator_clash il_operand + {$$ = new il_simple_operation_c($1, $2, locloc(@$));} +/* NOTE: the line + * | il_simple_operator + * already contains the 'NOT' operator, as well as all the + * expression operators ('MOD', 'AND', etc...), all of which + * may also be a function name! This means that these operators/functions, + * without any operands, could be reduced to either an operator or a + * function call. + * + * I (Mario) have chosen to reduce it to an operator. + * In order to do this, we must remove from the syntax that defines + * function calls all the functions whose names clash with the IL operators. + * + * The line + * | function_name + * has been replaced with the lines + * | function_name_no_clashes + * in order to include all possible function names except + * those whose names coincide with operators !! + */ +| function_name_no_clashes + {$$ = new il_function_call_c($1, NULL, locloc(@$));} +/* NOTE: the line + * | il_simple_operator il_operand + * already contains the 'NOT', 'MOD', etc. operators, followed by a single il_operand. + * However, this same code (MOD x) may also be reduced to a function call to the MOD + * function. This means that (MOD, AND,...) could be interpret as a function name + * or as an IL operator! This would lead us to a reduce/reduce conflict! + * + * I (Mario) have chosen to reduce it to an operand, rather than a function call. + * In order to do this, we must remove from the syntax that defines + * function calls all the functions whose names clash with the IL operators. + * + * The line + * | function_name il_operand_list + * has been replaced with the line + * | function_name_no_clashes il_operand_list + * in order to include all possible function names except + * for the function names which clash with expression and simple operators. + * + * Note that: + * this alternative syntax does not cover the possibility of + * the function 'NOT', 'MOD', etc... being called with more than one il_operand, + * in which case it is always a function call, and not an IL instruction. + * We therefore need to include an extra rule where the + * function_name_expression_clashes and function_name_simpleop_clashes + * are followed by a il_operand_list with __two__ or more il_operands!! + */ +| function_name_no_clashes il_operand_list + {$$ = new il_function_call_c($1, $2, locloc(@$));} +| il_simple_operator_clash il_operand_list2 + {$$ = new il_function_call_c(il_operator_c_2_identifier_c($1), $2, locloc(@$));} +; + + + +il_expression: +// il_expr_operator '(' [il_operand] EOL {EOL} [simple_instr_list] ')' +/* + * Note: Bison is getting confused with the use of il_expr_operator, + * i.e. it is finding conflicts where there seemingly are really none. + * il_expr_operator was therefore replaced by the equivalent + * il_expr_operator_noclash | il_expr_operator_clash. + */ + il_expr_operator_noclash '(' eol_list ')' + {$$ = new il_expression_c($1, NULL, NULL, locloc(@$));} +| il_expr_operator_noclash '(' il_operand eol_list ')' + {$$ = new il_expression_c($1, $3, NULL, locloc(@$));} +| il_expr_operator_noclash '(' eol_list simple_instr_list ')' + {$$ = new il_expression_c($1, NULL, $4, locloc(@$));} +| il_expr_operator_noclash '(' il_operand eol_list simple_instr_list ')' + {$$ = new il_expression_c($1, $3, $5, locloc(@$));} +| il_expr_operator_clash '(' eol_list ')' + {$$ = new il_expression_c($1, NULL, NULL, locloc(@$));} +| il_expr_operator_clash '(' il_operand eol_list ')' + {$$ = new il_expression_c($1, $3, NULL, locloc(@$));} +| il_expr_operator_clash '(' il_operand eol_list simple_instr_list ')' + {$$ = new il_expression_c($1, $3, $5, locloc(@$));} +| il_expr_operator_clash_eol_list simple_instr_list ')' + {$$ = new il_expression_c($1, NULL, $2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| il_expr_operator_noclash '(' eol_list error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of IL expression."); yyerrok;} +| il_expr_operator_noclash '(' il_operand eol_list error + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL expression."); yyerrok;} +| il_expr_operator_noclash '(' eol_list simple_instr_list error + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL expression."); yyerrok;} +| il_expr_operator_noclash '(' il_operand eol_list simple_instr_list error + {$$ = NULL; print_err_msg(locl(@5), locf(@6), "')' missing at the end of IL expression."); yyerrok;} +| il_expr_operator_clash '(' il_operand eol_list error + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL expression."); yyerrok;} +| il_expr_operator_clash '(' il_operand eol_list simple_instr_list error + {$$ = NULL; print_err_msg(locl(@5), locf(@6), "')' missing at the end of IL expression."); yyerrok;} +| il_expr_operator_clash_eol_list simple_instr_list error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of IL expression."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_jump_operation: + il_jump_operator label + {$$ = new il_jump_operation_c($1, $2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| il_jump_operator error + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid label defined in IL jump operation."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_fb_call: +// il_call_operator fb_name ['(' (EOL {EOL} [il_param_list]) | [il_operand_list] ')'] + il_call_operator prev_declared_fb_name + {$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));} +| il_call_operator prev_declared_fb_name '(' ')' + {$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));} +| il_call_operator prev_declared_fb_name '(' eol_list ')' + {$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));} +| il_call_operator prev_declared_fb_name '(' il_operand_list ')' + {$$ = new il_fb_call_c($1, $2, $4, NULL, locloc(@$));} +| il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')' + {$$ = new il_fb_call_c($1, $2, NULL, $5, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| il_call_operator error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call.");} + else {print_err_msg(locf(@2), locl(@2), "invalid function block name in IL function block call."); yyclearin;} + yyerrok; + } +| il_call_operator '(' ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} +| il_call_operator '(' eol_list ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} +| il_call_operator '(' il_operand_list ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} +| il_call_operator '(' eol_list il_param_list ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} +| il_call_operator error '(' ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} +| il_call_operator error '(' eol_list ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} +| il_call_operator error '(' il_operand_list ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} +| il_call_operator error '(' eol_list il_param_list ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} +| il_call_operator prev_declared_fb_name ')' + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'(' missing after function block name defined in IL function block call."); yynerrs++;} +| il_call_operator prev_declared_fb_name il_operand_list ')' + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'(' missing after function block name defined in IL function block call."); yynerrs++;} +| il_call_operator prev_declared_fb_name '(' error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of IL function block call."); yyerrok;} +| il_call_operator prev_declared_fb_name '(' eol_list error + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL function block call."); yyerrok;} +| il_call_operator prev_declared_fb_name '(' il_operand_list error + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL function block call."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* NOTE: Please read note above the definition of function_name_without_clashes */ +il_formal_funct_call: +// function_name '(' EOL {EOL} [il_param_list] ')' +/* function_name '(' eol_list ')' */ +/* NOTE: il_formal_funct_call is only used in the definition of + * - il_incomplete_instruction + * - il_simple_instruction + * In both of the above, il_expression also + * shows up as another option. This means that the functions whose + * names clash with expressions, followed by '(' eol_list ')', are + * already included. We must therefore leave them out in this + * definition in order to remove reduce/reduce conflicts. + * + * In summary: 'MOD' '(' eol_list ')', and all other functions whose + * names clash with expressions may be interpreted by the syntax by + * two different routes. I (Mario) chose to interpret them + * as operators, rather than as function calls! + * (AND MOD OR XOR ADD DIV EQ GT GE LT LE MUL NE SUB) + */ + function_name_no_clashes '(' eol_list ')' + {$$ = new il_formal_funct_call_c($1, NULL, locloc(@$));} +| function_name_simpleop_clashes '(' eol_list ')' + {$$ = new il_formal_funct_call_c($1, NULL, locloc(@$));} +/* | function_name '(' eol_list il_param_list ')' */ +/* For the above syntax, we no longer have two ways of interpreting the + * same syntax. The above is always a function call! + * However, some of the functions that we may be calling + * may have the same name as an IL operator. This means that + * flex will be parsing them and handing them over to bison as + * IL operator tokens, and not as function name tokens. + * (when parsing ST, flex no longer recognizes IL operators, + * so will always return the correct function name, unless that + * name also coincides with an operator used in ST -> XOR, OR, MOD, AND, NOT) + * + * We must therefore interpret the IL operators as function names! + */ +| function_name_no_clashes '(' eol_list il_param_list ')' + {$$ = new il_formal_funct_call_c($1, $4, locloc(@$));} +| function_name_simpleop_clashes '(' eol_list il_param_list ')' + {$$ = new il_formal_funct_call_c($1, $4, locloc(@$));} +/* The following line should read: + * + * | function_name_expression_clashes '(' eol_list il_param_list ')' + * + * but the function_name_expression_clashes had to be first reduced to + * an intermediary symbol in order to remove a reduce/reduce conflict. + * In essence, the syntax requires more than one look ahead token + * in order to be parsed. We resolve this by reducing a collection of + * symbols into a temporary symbol (il_expr_operator_clash_eol_list), that + * will later be replaced by the correct symbol. The correct symbol will + * now be determined by a single look ahead token, as all the common + * symbols have been reduced to the temporary symbol + * il_expr_operator_clash_eol_list ! + * + * Unfortunately, this work around results in the wrong symbol + * being created for the abstract syntax tree. + * We need to figure out which symbol was created, destroy it, + * and create the correct symbol for our case. + * This is a lot of work, so I put it in a function + * at the end of this file... il_operator_c_2_identifier_c() + */ +| il_expr_operator_clash_eol_list il_param_list ')' + {$$ = new il_formal_funct_call_c(il_operator_c_2_identifier_c($1), $2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| function_name_no_clashes '(' eol_list error ')' + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid parameter list defined in IL formal function call."); yyerrok;} +| function_name_simpleop_clashes '(' eol_list error ')' + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid parameter list defined in IL formal function call."); yyerrok;} +| il_expr_operator_clash_eol_list error ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid parameter list defined in IL formal function call."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_expr_operator_clash_eol_list: + il_expr_operator_clash '(' eol_list + {$$ = $1;} +/* ERROR_CHECK_BEGIN */ +| il_expr_operator_clash '(' error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "EOL missing after '(' in IL instruction."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_operand: + variable +| enumerated_value +| constant +; + + +il_operand_list: + il_operand + {$$ = new il_operand_list_c(locloc(@$)); $$->add_element($1);} +| il_operand_list2 +; + + +/* List with 2 or more il_operands */ +il_operand_list2: + il_operand ',' il_operand + {$$ = new il_operand_list_c(locloc(@$)); $$->add_element($1); $$->add_element($3);} +| il_operand_list2 ',' il_operand + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| il_operand_list2 il_operand + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in IL operand list."); yynerrs++;} +| il_operand ',' error + {$$ = new il_operand_list_c(locloc(@$)); + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no operand defined in IL operand list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid operand name in IL operand list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +simple_instr_list: + il_simple_instruction + {$$ = new simple_instr_list_c(locloc(@$)); $$->add_element($1);} +| simple_instr_list il_simple_instruction + {$$ = $1; $$->add_element($2);} +; + + +il_simple_instruction: + il_simple_operation eol_list +| il_expression eol_list +| il_formal_funct_call eol_list +/* ERROR_CHECK_BEGIN */ +| il_expression error + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing after expression IL instruction."); yyerrok;} +| il_formal_funct_call error + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing after formal function call IL instruction."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* NOTE: the correct definition of il_param_list is + * il_param_list ::= {il_param_instruction} il_param_last_instruction + * + * where {...} denotes zero or many il_param_instruction's. + * + * We could do this by defining the following: + * il_param_list: il_param_instruction_list il_param_last_instruction; + * il_param_instruction_list : ** empty ** | il_param_instruction_list il_param_instruction; + * + * Unfortunately, the above leads to reduce/reduce conflicts. + * The chosen alternative (as follows) does not have any conflicts! + * il_param_list: il_param_last_instruction | il_param_instruction_list il_param_last_instruction; + * il_param_instruction_list : il_param_instruction_list | il_param_instruction_list il_param_instruction; + */ +il_param_list: + il_param_instruction_list il_param_last_instruction + {$$ = $1; $$->add_element($2);} +| il_param_last_instruction + {$$ = new il_param_list_c(locloc(@$)); $$->add_element($1);} +/* ERROR_CHECK_BEGIN */ +| il_param_instruction_list error + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid parameter assignment in parameter assignment list."); yyerrok;} +| il_param_last_instruction il_param_last_instruction + {$$ = new il_param_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "',' missing at the end of parameter assignment in parameter assignment list."); yynerrs++;} +| il_param_instruction_list il_param_last_instruction il_param_last_instruction + {$$ = $1; print_err_msg(locl(@2), locf(@3), "',' missing at the end of parameter assignment in parameter assignment list."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +/* Helper symbol for il_param_list */ +il_param_instruction_list: + il_param_instruction + {$$ = new il_param_list_c(locloc(@$)); $$->add_element($1);} +| il_param_instruction_list il_param_instruction + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| il_param_last_instruction il_param_instruction + {$$ = new il_param_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "',' missing at the end of parameter assignment in parameter assignment list."); yynerrs++;} +| il_param_instruction_list il_param_last_instruction il_param_instruction + {$$ = $1; print_err_msg(locl(@2), locf(@3), "',' missing at the end of parameter assignment in parameter assignment list."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +il_param_instruction: + il_param_assignment ',' eol_list +| il_param_out_assignment ',' eol_list +/* ERROR_CHECK_BEGIN */ +| il_param_assignment ',' error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "EOL missing at the end of parameter assignment in parameter assignment list."); yyerrok;} +| il_param_out_assignment ',' error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "EOL missing at the end of parameter out assignment in parameter assignment list."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_param_last_instruction: + il_param_assignment eol_list +| il_param_out_assignment eol_list +/* ERROR_CHECK_BEGIN */ +| il_param_assignment error + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing at the end of last parameter assignment in parameter assignment list."); yyerrok;} +| il_param_out_assignment error + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing at the end of last parameter out assignment in parameter assignment list."); yyerrok;} +/* ERROR_CHECK_END */ + +; + + +il_param_assignment: + il_assign_operator il_operand + {$$ = new il_param_assignment_c($1, $2, NULL, locloc(@$));} +| il_assign_operator '(' eol_list simple_instr_list ')' + {$$ = new il_param_assignment_c($1, NULL, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| error il_operand + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid operator in parameter assignment."); yyerrok;} +| error '(' eol_list simple_instr_list ')' + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid operator in parameter assignment."); yyerrok;} +| il_assign_operator error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no operand defined in parameter assignment.");} + else {print_err_msg(locf(@2), locl(@2), "invalid operand in parameter assignment."); yyclearin;} + yyerrok; + } +| il_assign_operator '(' eol_list ')' + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no instruction list defined in parameter assignment."); yynerrs++;} +| il_assign_operator '(' eol_list error ')' + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid instruction list defined in parameter assignment."); yyerrok;} +| il_assign_operator '(' eol_list simple_instr_list error + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of instruction list defined in parameter assignment."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_param_out_assignment: + il_assign_out_operator variable + {$$ = new il_param_out_assignment_c($1, $2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| il_assign_out_operator error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no variable defined in IL operand list.");} + else {print_err_msg(locf(@2), locl(@2), "invalid variable in IL operand list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +/*******************/ +/* B 2.2 Operators */ +/*******************/ +sendto_identifier: sendto_identifier_token {$$ = new identifier_c($1, locloc(@$));}; + + +/* NOTE: + * The spec includes the operator 'EQ ' + * Note that EQ is followed by a space. + * I am considering this a typo, and defining the operator + * as 'EQ' + * (Mario) + */ +LD_operator: LD {$$ = new LD_operator_c(locloc(@$));}; +LDN_operator: LDN {$$ = new LDN_operator_c(locloc(@$));}; +ST_operator: ST {$$ = new ST_operator_c(locloc(@$));}; +STN_operator: STN {$$ = new STN_operator_c(locloc(@$));}; +NOT_operator: NOT {$$ = new NOT_operator_c(locloc(@$));}; +S_operator: S {$$ = new S_operator_c(locloc(@$));}; +R_operator: R {$$ = new R_operator_c(locloc(@$));}; +S1_operator: S1 {$$ = new S1_operator_c(locloc(@$));}; +R1_operator: R1 {$$ = new R1_operator_c(locloc(@$));}; +CLK_operator: CLK {$$ = new CLK_operator_c(locloc(@$));}; +CU_operator: CU {$$ = new CU_operator_c(locloc(@$));}; +CD_operator: CD {$$ = new CD_operator_c(locloc(@$));}; +PV_operator: PV {$$ = new PV_operator_c(locloc(@$));}; +IN_operator: IN {$$ = new IN_operator_c(locloc(@$));}; +PT_operator: PT {$$ = new PT_operator_c(locloc(@$));}; +AND_operator: AND {$$ = new AND_operator_c(locloc(@$));}; +AND2_operator: AND2 {$$ = new AND_operator_c(locloc(@$));}; /* '&' in the source code! */ +OR_operator: OR {$$ = new OR_operator_c(locloc(@$));}; +XOR_operator: XOR {$$ = new XOR_operator_c(locloc(@$));}; +ANDN_operator: ANDN {$$ = new ANDN_operator_c(locloc(@$));}; +ANDN2_operator: ANDN2 {$$ = new ANDN_operator_c(locloc(@$));}; /* '&N' in the source code! */ +ORN_operator: ORN {$$ = new ORN_operator_c(locloc(@$));}; +XORN_operator: XORN {$$ = new XORN_operator_c(locloc(@$));}; +ADD_operator: ADD {$$ = new ADD_operator_c(locloc(@$));}; +SUB_operator: SUB {$$ = new SUB_operator_c(locloc(@$));}; +MUL_operator: MUL {$$ = new MUL_operator_c(locloc(@$));}; +DIV_operator: DIV {$$ = new DIV_operator_c(locloc(@$));}; +MOD_operator: MOD {$$ = new MOD_operator_c(locloc(@$));}; +GT_operator: GT {$$ = new GT_operator_c(locloc(@$));}; +GE_operator: GE {$$ = new GE_operator_c(locloc(@$));}; +EQ_operator: EQ {$$ = new EQ_operator_c(locloc(@$));}; +LT_operator: LT {$$ = new LT_operator_c(locloc(@$));}; +LE_operator: LE {$$ = new LE_operator_c(locloc(@$));}; +NE_operator: NE {$$ = new NE_operator_c(locloc(@$));}; +CAL_operator: CAL {$$ = new CAL_operator_c(locloc(@$));}; +CALC_operator: CALC {$$ = new CALC_operator_c(locloc(@$));}; +CALCN_operator: CALCN {$$ = new CALCN_operator_c(locloc(@$));}; +RET_operator: RET {$$ = new RET_operator_c(locloc(@$));}; +RETC_operator: RETC {$$ = new RETC_operator_c(locloc(@$));}; +RETCN_operator: RETCN {$$ = new RETCN_operator_c(locloc(@$));}; +JMP_operator: JMP {$$ = new JMP_operator_c(locloc(@$));}; +JMPC_operator: JMPC {$$ = new JMPC_operator_c(locloc(@$));}; +JMPCN_operator: JMPCN {$$ = new JMPCN_operator_c(locloc(@$));}; + + +il_simple_operator: + il_simple_operator_clash +| il_simple_operator_noclash +; + + +il_simple_operator_noclash: + LD_operator +| LDN_operator +| ST_operator +| STN_operator +| S_operator +| R_operator +| S1_operator +| R1_operator +| CLK_operator +| CU_operator +| CD_operator +| PV_operator +| IN_operator +| PT_operator +| il_expr_operator_noclash +; + + +il_simple_operator_clash: + il_simple_operator_clash1 +| il_simple_operator_clash2 +; + +il_simple_operator_clash1: + NOT_operator +; + +il_simple_operator_clash2: + il_expr_operator_clash +; + + +/* +il_expr_operator: + il_expr_operator_noclash +| il_expr_operator_clash +; +*/ + +il_expr_operator_clash: + AND_operator +| OR_operator +| XOR_operator +| ADD_operator +| SUB_operator +| MUL_operator +| DIV_operator +| MOD_operator +| GT_operator +| GE_operator +| EQ_operator +| LT_operator +| LE_operator +| NE_operator +; + + +il_expr_operator_noclash: + ANDN_operator +| ANDN2_operator /* string '&N' in source code! */ +| AND2_operator /* string '&' in source code! */ +| ORN_operator +| XORN_operator +; + + + + +il_assign_operator: +/* variable_name ASSIGN */ + any_identifier ASSIGN + {$$ = new il_assign_operator_c($1, locloc(@$));} +| en_identifier ASSIGN + {$$ = new il_assign_operator_c($1, locloc(@$));} +| S1_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +| R1_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +| CLK_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +| CU_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +| CD_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +| PV_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +| IN_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +| PT_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| error ASSIGN + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid parameter defined in parameter assignment."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_assign_out_operator: +/* variable_name SENDTO */ +/* any_identifier SENDTO */ + sendto_identifier SENDTO + {$$ = new il_assign_out_operator_c(NULL, $1, locloc(@$));} +/* The following is not required, as the sendto_identifier_token returned by flex will + * also include the 'ENO' identifier. + * The resulting abstract syntax tree is identical with or without this following rule, + * as both the eno_identifier and the sendto_identifier are stored as + * an identifier_c !! + * + * To understand why we must even explicitly consider the use of ENO here, + * please read the comment above the definition of 'variable' in section B1.4 for details. + */ +/* +| eno_identifier SENDTO + {$$ = new il_assign_out_operator_c(NULL, $1, locloc(@$));} +*/ +/*| NOT variable_name SENDTO */ +| NOT sendto_identifier SENDTO + {$$ = new il_assign_out_operator_c(new not_paramassign_c(locloc(@1)), $2, locloc(@$));} +/* The following is not required, as the sendto_identifier_token returned by flex will + * also include the 'ENO' identifier. + * The resulting abstract syntax tree is identical with or without this following rule, + * as both the eno_identifier and the sendto_identifier are stored as + * an identifier_c !! + * + * To understand why we must even explicitly consider the use of ENO here, + * please read the comment above the definition of 'variable' in section B1.4 for details. + * + * NOTE: Removing the following rule also removes a shift/reduce conflict from the parser. + * This conflict is not really an error/ambiguity in the syntax, but rather + * due to the fact that more than a single look-ahead token would be required + * to correctly parse the syntax, something that bison does not support. + * + * The shift/reduce conflict arises because bison does not know whether + * to parse the 'NOT ENO' in the following code + * LD 1 + * funct_name ( + * NOT ENO => bool_var, + * EN := TRUE + * ) + * as either a il_param_assignment (wrong!) or an il_param_out_assignment.(correct). + * The '=>' delimiter (known as SEND_TO in this iec.y file) is a dead giveaway that + * it should be parsed as an il_param_out_assignment, but still, bison gets confused! + * Bison considers the possibility of reducing the 'NOT ENO' as an NOT_operator with + * the 'ENO' operand + * (NOT_operator -> il_simple_operator -> il_simple_operation -> il_simple_instruction -> + * -> simple_instr_list -> il_param_assignment) + * instead of reducing it to an il_param_out_operator. + * ( il_param_out_operator -> il_param_out_assignment) + * + * Note that the shift/reduce conflict only manifests itself in the il_formal_funct_call, + * where both the il_param_out_assignment and il_param_assignment are used! + * + * il_param_out_assignment --+--> il_param_instruction -> il_param_instruction_list --+ + * | | + * il_param_assignment --+ | + * | + * il_formal_funct_call <- il_param_list <-+ + * + */ +/* +| NOT eno_identifier SENDTO + {$$ = new il_assign_out_operator_c(new not_paramassign_c(locloc(@1)), $2, locloc(@$));} +*/ +/* ERROR_CHECK_BEGIN */ +| error SENDTO + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid parameter defined in parameter out assignment."); yyerrok;} +| NOT SENDTO + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no parameter defined in parameter out assignment."); yynerrs++;} +| NOT error SENDTO + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid parameter defined in parameter out assignment."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_call_operator: + CAL_operator +| CALC_operator +| CALCN_operator +; + + +il_return_operator: + RET_operator +| RETC_operator +| RETCN_operator +; + + +il_jump_operator: + JMP_operator +| JMPC_operator +| JMPCN_operator +; + + +/***********************/ +/* B 3.1 - Expressions */ +/***********************/ +expression: + xor_expression +| expression OR xor_expression + {$$ = new or_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| expression OR error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'OR' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'OR' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +xor_expression: + and_expression +| xor_expression XOR and_expression + {$$ = new xor_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| xor_expression XOR error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'XOR' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'XOR' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +and_expression: + comparison +| and_expression '&' comparison + {$$ = new and_expression_c($1, $3, locloc(@$));} +| and_expression AND comparison + {$$ = new and_expression_c($1, $3, locloc(@$));} +/* NOTE: The lexical parser never returns the token '&'. + * The '&' string is interpreted by the lexcial parser as the token + * AND2! + * This means that the first rule with '&' is actually not required, + * but we leave it in nevertheless just in case we later decide + * to remove the AND2 token... + */ +| and_expression AND2 comparison + {$$ = new and_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| and_expression '&' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '&' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '&' in ST expression."); yyclearin;} + yyerrok; + } +| and_expression AND error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'AND' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'AND' in ST expression."); yyclearin;} + yyerrok; + } +| and_expression AND2 error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '&' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '&' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +comparison: + equ_expression +| comparison '=' equ_expression + {$$ = new equ_expression_c($1, $3, locloc(@$));} +| comparison OPER_NE equ_expression + {$$ = new notequ_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| comparison '=' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '=' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '=' in ST expression."); yyclearin;} + yyerrok; + } +| comparison OPER_NE error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '<>' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '<>' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +equ_expression: + add_expression +| equ_expression '<' add_expression + {$$ = new lt_expression_c($1, $3, locloc(@$));} +| equ_expression '>' add_expression + {$$ = new gt_expression_c($1, $3, locloc(@$));} +| equ_expression OPER_LE add_expression + {$$ = new le_expression_c($1, $3, locloc(@$));} +| equ_expression OPER_GE add_expression + {$$ = new ge_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| equ_expression '<' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '<' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '<' in ST expression."); yyclearin;} + yyerrok; + } +| equ_expression '>' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '>' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '>' in ST expression."); yyclearin;} + yyerrok; + } +| equ_expression OPER_LE error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '<=' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '<=' in ST expression."); yyclearin;} + yyerrok; + } +| equ_expression OPER_GE error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '>=' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '>=' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* Not required... +comparison_operator: '<' | '>' | '>=' '<=' +*/ + +add_expression: + term +| add_expression '+' term + {$$ = new add_expression_c($1, $3, locloc(@$));} +| add_expression '-' term + {$$ = new sub_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| add_expression '+' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '+' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '+' in ST expression."); yyclearin;} + yyerrok; + } +| add_expression '-' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '-' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '-' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* Not required... +add_operator: '+' | '-' +*/ + +term: + power_expression +| term '*' power_expression + {$$ = new mul_expression_c($1, $3, locloc(@$));} +| term '/' power_expression + {$$ = new div_expression_c($1, $3, locloc(@$));} +| term MOD power_expression + {$$ = new mod_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| term '*' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '*' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '*' in ST expression."); yyclearin;} + yyerrok; + } +| term '/' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '/' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '/' in ST expression."); yyclearin;} + yyerrok; + } +| term MOD error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'MOD' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'MOD' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* Not required... +multiply_operator: '*' | '/' | 'MOD' +*/ + +power_expression: + unary_expression +| power_expression OPER_EXP unary_expression + {$$ = new power_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| power_expression OPER_EXP error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '**' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '**' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +unary_expression: + non_negative_primary_expression +| '-' non_negative_primary_expression + {$$ = new neg_expression_c($2, locloc(@$));} +| NOT primary_expression + {$$ = new not_expression_c($2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| '-' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no expression defined after '-' in ST expression.");} + else {print_err_msg(locf(@2), locl(@2), "invalid expression after '-' in ST expression."); yyclearin;} + yyerrok; + } +| NOT error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no expression defined after 'NOT' in ST expression.");} + else {print_err_msg(locf(@2), locl(@2), "invalid expression after 'NOT' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* Not required... +unary_operator: '-' | 'NOT' +*/ + + +/* NOTE: using constant as a possible symbol for primary_expression + * leads to a reduce/reduce conflict. + * + * The text '-9' may be parsed as either a + * expression<-primary_expression<-constant<-signed_integer + * (i.e. the constant 9 negative) + * OR + * expression<-unary_expression<-constant<-integer + * (i.e. the constant 9, preceded by a unary negation) + * + * To remove the conflict, we only allow constants without + * a preceding '-' to be used in primary_expression + * (i.e. as a parameter to the unary negation operator) + */ +/* NOTE: We use enumerated_value_without_identifier instead of enumerated_value + * in order to remove a reduce/reduce conflict between reducing an + * identifier to a variable or an enumerated_value. + * + * This change follows the IEC specification. The specification seems to + * imply (by introducing syntax that allows to unambiguosly reference an + * enumerated value - enum_type#enum_value) that in case the same identifier is used + * for a variable and an enumerated value, then the variable shall be + * considered. + */ +non_negative_primary_expression: + non_negative_constant +//| enumerated_value_without_identifier +| enumerated_value +| variable +| '(' expression ')' + {$$ = $2;} +| function_invocation +/* ERROR_CHECK_BEGIN */ +| '(' expression error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of expression in ST expression."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +primary_expression: + constant +//| enumerated_value_without_identifier +| enumerated_value +| variable +| '(' expression ')' + {$$ = $2;} +| function_invocation +/* ERROR_CHECK_BEGIN */ +| '(' expression error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of expression in ST expression."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + +/* intermediate helper symbol for primary_expression */ +/* NOTE: function_name includes the standard function name 'NOT' ! + * This introduces a reduce/reduce conflict, as NOT(var) + * may be parsed as either a function_invocation, or a + * unary_expression. + * + * I (Mario) have opted to remove the possible reduction + * to function invocation, which means replacing the rule + * function_name '(' param_assignment_list ')' + * with + * function_name_no_NOT_clashes '(' param_assignment_list ')' + * + * Notice how the new rule does not include the situation where + * the function NOT is called with more than one parameter, which + * the original rule does include! Callinf the NOT function with more + * than one argument is probably a semantic error anyway, so it + * doesn't make much sense to take it into account. + * + * Nevertheless, if we were to to it entirely correctly, + * leaving the semantic checks for the next compiler stage, + * this syntax parser would need to include such a possibility. + * + * We will leave this out for now. No need to complicate the syntax + * more than the specification does by contradicting itself, and + * letting names clash! + */ +function_invocation: +/* function_name '(' [param_assignment_list] ')' */ + function_name_no_NOT_clashes '(' param_assignment_formal_list ')' + {$$ = new function_invocation_c($1, $3, NULL, locloc(@$));} +| function_name_no_NOT_clashes '(' param_assignment_nonformal_list ')' + {$$ = new function_invocation_c($1, NULL, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| function_name_no_NOT_clashes param_assignment_formal_list ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function name in ST expression."); yynerrs++;} +| function_name_no_NOT_clashes '(' ')' + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no parameter defined in function invocation of ST expression."); yynerrs++;} +| function_name_no_NOT_clashes '(' error ')' + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid parameter(s) defined in function invocation of ST expression."); yyerrok;} +| function_name_no_NOT_clashes '(' param_assignment_formal_list error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of function invocation in ST expression."); yyerrok;} +| function_name_no_NOT_clashes '(' param_assignment_nonformal_list error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of function invocation in ST expression."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/********************/ +/* B 3.2 Statements */ +/********************/ +statement_list: + statement ';' + {$$ = new statement_list_c(locloc(@$)); $$->add_element($1);} +| any_pragma + {$$ = new statement_list_c(locloc(@$)); $$->add_element($1);} +| statement_list statement ';' + {$$ = $1; $$->add_element($2);} +| statement_list any_pragma + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| statement error + {$$ = new statement_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at the end of statement in ST statement."); yyerrok;} +| statement_list statement error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of statement in ST statement."); yyerrok;} +| statement_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid statement in ST statement."); yyerrok;} +| statement_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after statement in ST statement."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +statement: + assignment_statement +| subprogram_control_statement +| selection_statement +| iteration_statement +; + + +/*********************************/ +/* B 3.2.1 Assignment Statements */ +/*********************************/ +assignment_statement: + variable ASSIGN expression + {$$ = new assignment_statement_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| error ASSIGN expression + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid variable before ':=' in ST assignment statement."); yyerrok;} +| variable ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after ':=' in ST assignment statement.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after ':=' in ST assignment statement."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + + +/*****************************************/ +/* B 3.2.2 Subprogram Control Statements */ +/*****************************************/ +subprogram_control_statement: + fb_invocation +| return_statement +; + +return_statement: + RETURN {$$ = new return_statement_c(locloc(@$));} +; + + + +fb_invocation: + prev_declared_fb_name '(' ')' + {$$ = new fb_invocation_c($1, NULL, NULL, locloc(@$)); } +| prev_declared_fb_name '(' param_assignment_formal_list ')' + {$$ = new fb_invocation_c($1, $3, NULL, locloc(@$));} +| prev_declared_fb_name '(' param_assignment_nonformal_list ')' + {$$ = new fb_invocation_c($1, NULL, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| prev_declared_fb_name ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function block name in ST statement."); yynerrs++;} +| prev_declared_fb_name param_assignment_formal_list ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function block name in ST statement."); yynerrs++;} +| prev_declared_fb_name '(' error ')' + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid parameter list in function block invocation in ST statement."); yyerrok;} +| prev_declared_fb_name '(' error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing after parameter list of function block invocation in ST statement."); yyerrok;} +| prev_declared_fb_name '(' param_assignment_formal_list error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing after parameter list of function block invocation in ST statement."); yyerrok;} +| prev_declared_fb_name '(' param_assignment_nonformal_list error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing after parameter list of function block invocation in ST statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* helper symbol for + * - fb_invocation + * - function_invocation + */ +param_assignment_formal_list: + param_assignment_formal + {$$ = new param_assignment_list_c(locloc(@$)); $$->add_element($1);} +| param_assignment_formal_list ',' param_assignment_formal + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| param_assignment_formal_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no parameter assignment defined in ST parameter assignment list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid parameter assignment in ST parameter assignment list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* helper symbol for + * - fb_invocation + * - function_invocation + */ +param_assignment_nonformal_list: + param_assignment_nonformal + {$$ = new param_assignment_list_c(locloc(@$)); $$->add_element($1);} +| param_assignment_nonformal_list ',' param_assignment_nonformal + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| param_assignment_nonformal_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no parameter assignment defined in ST parameter assignment list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid parameter assignment in ST parameter assignment list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +/* NOTE: According to the IEC 61131-3 standard, there are two possible + * syntaxes for calling function blocks within ST. + * The formal method has the form: + * fb ( invar := x, inoutvar := var1, outvar => var2); + * The non-formal method has the form: + * fb (x, var1, var2); + * In the text of IEC 61131-3 (where the semantics are defined), + * it is obvious that mixing the two syntaxes is considered incorrect. + * The following should therefore be incorrect: + * fb ( invar := x, var1, var2); + * However, according to the syntax definition, as defined in IEC 61131-3, + * mixing the formal and non-formal methods of invocation is allowed. + * We have two alternatives: + * (a) implement the syntax here in iec.y according to the standard, + * and leave it to the semantic analyser stage to find this error + * (b) or implement the syntax in iec.y correctly, not allowing + * the mixing of formal and non-formal invocation syntaxes. + * Considering that this is a syntax issue, and not semantic issue, + * I (Mario) have decided to go with alternative (a). + * In other words, in iec.y we do not follow the syntax as defined in + * Annex B of the IEC 61131-3 standard, but rather implement + * the syntax also taking into account the textual part of the standard too. + */ +/* +param_assignment: + variable_name ASSIGN expression +*/ +param_assignment_nonformal: + expression +; + + +param_assignment_formal: + any_identifier ASSIGN expression + {$$ = new input_variable_param_assignment_c($1, $3, locloc(@$));} +| en_identifier ASSIGN expression + {$$ = new input_variable_param_assignment_c($1, $3, locloc(@$));} +/*| variable_name SENDTO variable */ +/*| any_identifier SENDTO variable */ +| sendto_identifier SENDTO variable + {$$ = new output_variable_param_assignment_c(NULL, $1, $3, locloc(@$));} +/* The following is not required, as the sendto_identifier_token returned by flex will + * also include the 'ENO' identifier. + * The resulting abstract syntax tree is identical with or without this following rule, + * as both the eno_identifier and the sendto_identifier are stored as + * an identifier_c !! + * + * To understand why we must even explicitly consider the use of ENO here, + * please read the comment above the definition of 'variable' in section B1.4 for details. + */ +/* +| eno_identifier SENDTO variable + {$$ = new output_variable_param_assignment_c(NULL, $1, $3, locloc(@$));} +*/ +/*| NOT variable_name SENDTO variable */ +/*| NOT any_identifier SENDTO variable*/ +| NOT sendto_identifier SENDTO variable + {$$ = new output_variable_param_assignment_c(new not_paramassign_c(locloc(@$)), $2, $4, locloc(@$));} +/* The following is not required, as the sendto_identifier_token returned by flex will + * also include the 'ENO' identifier. + * The resulting abstract syntax tree is identical with or without this following rule, + * as both the eno_identifier and the sendto_identifier are stored as + * an identifier_c !! + * + * To understand why we must even explicitly consider the use of ENO here, + * please read the comment above the definition of 'variable' in section B1.4 for details. + */ +/* +| NOT eno_identifier SENDTO variable + {$$ = new output_variable_param_assignment_c(new not_paramassign_c(locloc(@$)), $2, $4, locloc(@$));} +*/ +/* ERROR_CHECK_BEGIN */ +| any_identifier ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter assignment.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter assignment."); yyclearin;} + yyerrok; + } +| en_identifier ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter assignment.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter assignment."); yyclearin;} + yyerrok; + } +| sendto_identifier SENDTO error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter out assignment.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter out assignment."); yyclearin;} + yyerrok; + } +/* +| eno_identifier SENDTO error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter out assignment.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter out assignment."); yyclearin;} + yyerrok; + } +*/ +| NOT SENDTO variable + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no parameter name defined in ST formal parameter out negated assignment."); yynerrs++;} +| NOT error SENDTO variable + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid parameter name defined in ST formal parameter out negated assignment."); yyerrok;} +| NOT sendto_identifier SENDTO error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no expression defined in ST formal parameter out negated assignment.");} + else {print_err_msg(locf(@4), locl(@4), "invalid expression in ST formal parameter out negated assignment."); yyclearin;} + yyerrok; + } +/* +| NOT eno_identifier SENDTO error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no expression defined in ST formal parameter out negated assignment.");} + else {print_err_msg(locf(@4), locl(@4), "invalid expression in ST formal parameter out negated assignment."); yyclearin;} + yyerrok; + } +*/ +/* ERROR_CHECK_END */ +; + + + + + +/********************************/ +/* B 3.2.3 Selection Statements */ +/********************************/ +selection_statement: + if_statement +| case_statement +; + + +if_statement: + IF expression THEN statement_list elseif_statement_list END_IF + {$$ = new if_statement_c($2, $4, $5, NULL, locloc(@$));} +| IF expression THEN statement_list elseif_statement_list ELSE statement_list END_IF + {$$ = new if_statement_c($2, $4, $5, $7, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| IF THEN statement_list elseif_statement_list END_IF + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'IF' statement."); yynerrs++;} +| IF THEN statement_list elseif_statement_list ELSE statement_list END_IF + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'IF' statement."); yynerrs++;} +| IF error THEN statement_list elseif_statement_list END_IF + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'IF' statement."); yyerrok;} +| IF error THEN statement_list elseif_statement_list ELSE statement_list END_IF + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'IF' statement."); yyerrok;} +| IF expression error statement_list elseif_statement_list END_IF + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'THEN' after test expression in ST 'IF' statement."); yyerrok;} +| IF expression error statement_list elseif_statement_list ELSE statement_list END_IF + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'THEN' after test expression in ST 'IF' statement."); yyerrok;} +| IF expression THEN elseif_statement_list END_IF + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no statement defined after 'THEN' in ST 'IF' statement."); yynerrs++;} +| IF expression THEN elseif_statement_list ELSE statement_list END_IF + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no statement defined after 'THEN' in ST 'IF' statement."); yynerrs++;} +| IF expression THEN statement_list elseif_statement_list ELSE END_IF + {$$ = NULL; print_err_msg(locl(@6), locf(@7), "no statement defined after 'ELSE' in ST 'IF' statement."); yynerrs++;} +| IF expression THEN statement_list elseif_statement_list ELSE error END_IF + {$$ = NULL; print_err_msg(locf(@7), locl(@7), "invalid statement defined after 'ELSE' in ST 'IF' statement."); yynerrs++; yyerrok;} +| IF expression error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed 'IF' statement in ST."); yyerrok;} +| IF expression THEN statement_list elseif_statement_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'IF' statement in ST."); yynerrs++;} +| IF expression THEN statement_list elseif_statement_list ELSE statement_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'IF' statement in ST."); yynerrs++;} +| IF error END_IF + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'IF' statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for if_statement */ +elseif_statement_list: + /* empty */ + {$$ = new elseif_statement_list_c(locloc(@$));} +| elseif_statement_list elseif_statement + {$$ = $1; $$->add_element($2);} +; + +/* helper symbol for elseif_statement_list */ +elseif_statement: + ELSIF expression THEN statement_list + {$$ = new elseif_statement_c($2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| ELSIF THEN statement_list + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined for 'ELSEIF' statement in ST 'IF' statement."); yynerrs++;} +| ELSIF error THEN statement_list + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for 'ELSEIF' statement in ST 'IF' statement."); yyerrok;} +| ELSIF expression error statement_list + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'THEN' after test expression in 'ELSEIF' statement of ST 'IF' statement."); yyerrok;} +| ELSIF expression THEN error + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid statement list in 'ELSEIF' statement of ST 'IF' statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +case_statement: + CASE expression OF case_element_list END_CASE + {$$ = new case_statement_c($2, $4, NULL, locloc(@$));} +| CASE expression OF case_element_list ELSE statement_list END_CASE + {$$ = new case_statement_c($2, $4, $6, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| CASE OF case_element_list END_CASE + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'CASE' statement."); yynerrs++;} +| CASE OF case_element_list ELSE statement_list END_CASE + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'CASE' statement."); yynerrs++;} +| CASE error OF case_element_list END_CASE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'CASE' statement."); yyerrok;} +| CASE error OF case_element_list ELSE statement_list END_CASE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'CASE' statement."); yyerrok;} +| CASE expression error case_element_list END_CASE + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'OF' after test expression in ST 'CASE' statement."); yyerrok;} +| CASE expression error case_element_list ELSE statement_list END_CASE + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'OF' after test expression in ST 'CASE' statement."); yyerrok;} +| CASE expression OF END_CASE + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no case element(s) defined after 'OF' in ST 'CASE' statement."); yynerrs++;} +| CASE expression OF ELSE statement_list END_CASE + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no case element(s) defined after 'OF' in ST 'CASE' statement."); yynerrs++;} +| CASE expression OF error END_CASE + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid case element(s) defined after 'OF' in ST 'CASE' statement."); yyerrok;} +| CASE expression OF error ELSE statement_list END_CASE + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid case element(s) defined after 'OF' in ST 'CASE' statement."); yyerrok;} +| CASE expression OF case_element_list ELSE END_CASE + {$$ = NULL; print_err_msg(locl(@5), locf(@6), "no statement defined after 'ELSE' in ST 'CASE' statement."); yynerrs++;} +| CASE expression OF case_element_list ELSE error END_CASE + {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid statement defined after 'ELSE' in ST 'CASE' statement."); yyerrok;} +| CASE expression error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed 'CASE' statement in ST."); yyerrok;} +| CASE expression OF case_element_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'CASE' statement in ST."); yynerrs++;} +| CASE expression OF case_element_list ELSE statement_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'CASE' statement in ST."); yynerrs++;} +| CASE error END_CASE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'CASE' statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* helper symbol for case_statement */ +case_element_list: + case_element + {$$ = new case_element_list_c(locloc(@$)); $$->add_element($1);} +| case_element_list case_element + {$$ = $1; $$->add_element($2);} +; + + +case_element: + case_list ':' statement_list + {$$ = new case_element_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| case_list statement_list + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after case list in ST 'CASE' statement."); yynerrs++;} +| case_list ':' error + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid statement in case element of ST 'CASE' statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +case_list: + case_list_element + {$$ = new case_list_c(locloc(@$)); $$->add_element($1);} +| case_list ',' case_list_element + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| case_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no case defined in case list of ST parameter assignment list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid case in case list of ST parameter assignment list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +case_list_element: + signed_integer +| subrange +| enumerated_value +; + + + + + +/********************************/ +/* B 3.2.4 Iteration Statements */ +/********************************/ +iteration_statement: + for_statement +| while_statement +| repeat_statement +| exit_statement +; + + +for_statement: + FOR control_variable ASSIGN expression TO expression BY expression DO statement_list END_FOR + {$$ = new for_statement_c($2, $4, $6, $8, $10, locloc(@$));} +| FOR control_variable ASSIGN expression TO expression DO statement_list END_FOR + {$$ = new for_statement_c($2, $4, $6, NULL, $8, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| FOR ASSIGN expression TO expression BY expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no control variable defined in ST 'FOR' statement."); yynerrs++;} +| FOR ASSIGN expression TO expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no control variable defined in ST 'FOR' statement."); yynerrs++;} +| FOR error ASSIGN expression TO expression BY expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid control variable defined for ST 'FOR' statement."); yyerrok;} +| FOR error ASSIGN expression TO expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid control variable defined for ST 'FOR' statement."); yyerrok;} +| FOR control_variable expression TO expression BY expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':=' missing between control variable and start expression in ST 'FOR' statement."); yynerrs++;} +| FOR control_variable expression TO expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':=' missing between control variable and start expression in ST 'FOR' statement."); yynerrs++;} +| FOR control_variable error expression TO expression BY expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting ':=' between control variable and start expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable error expression TO expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting ':=' between control variable and start expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN TO expression BY expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no start expression defined in ST 'FOR' statement."); yynerrs++;} +| FOR control_variable ASSIGN TO expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no start expression defined in ST 'FOR' statement."); yynerrs++;} +| FOR control_variable ASSIGN error TO expression BY expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid start expression defined in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN error TO expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid start expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN expression error expression BY expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@5), locl(@5), "expecting 'TO' between start expression and end expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN expression error expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@5), locl(@5), "expecting 'TO' between start expression and end expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN expression TO expression error expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@7), locl(@7), "expecting 'BY' between end expression and step expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN expression TO expression BY expression error statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@9), locl(@9), "expecting 'DO' after step expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN expression TO expression error statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@7), locl(@7), "expecting 'DO' after end expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN expression TO expression BY expression DO END_FOR + {$$ = NULL; print_err_msg(locl(@9), locf(@10), "no statement(s) defined after 'DO' in ST 'FOR' statement."); yynerrs++;} +| FOR control_variable ASSIGN expression TO expression DO END_FOR + {$$ = NULL; print_err_msg(locl(@7), locf(@8), "no statement(s) defined after 'DO' in ST 'FOR' statement."); yynerrs++;} +| FOR control_variable ASSIGN expression TO expression BY expression DO error END_FOR + {$$ = NULL; print_err_msg(locf(@10), locl(@10), "invalid statement(s) defined after 'DO' in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN expression TO expression DO error END_FOR + {$$ = NULL; print_err_msg(locf(@8), locl(@8), "invalid statement(s) defined after 'DO' in ST 'FOR' statement."); yyerrok;} +| FOR control_variable error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yyerrok;} +| FOR control_variable ASSIGN expression error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yyerrok;} +| FOR control_variable ASSIGN expression TO expression DO statement_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yynerrs++;} +| FOR control_variable ASSIGN expression TO expression BY expression error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yyerrok;} +| FOR control_variable ASSIGN expression TO expression BY expression DO statement_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yynerrs++;} +| FOR error END_FOR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'FOR' statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* The spec has the syntax + * control_variable: identifier; + * but then defines the semantics of control_variable + * (Section 3.3.2.4) as being of an integer type + * (e.g., SINT, INT, or DINT). + * + * Obviously this presuposes that the control_variable + * must have been declared in some VAR .. END_VAR + * We must therefore change the syntax to read + * control_variable: prev_declared_variable_name; + * + * If we don't, then the correct use of any previosuly declared + * variable would result in an incorrect syntax error +*/ +control_variable: + prev_declared_variable_name + {$$ = new symbolic_variable_c($1,locloc(@$));}; +// control_variable: identifier {$$ = $1;}; + +/* Integrated directly into for_statement */ +/* +for_list: + expression TO expression [BY expression] +; +*/ + + +while_statement: + WHILE expression DO statement_list END_WHILE + {$$ = new while_statement_c($2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| WHILE DO statement_list END_WHILE + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'WHILE' statement."); yynerrs++;} +| WHILE error DO statement_list END_WHILE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'WHILE' statement."); yyerrok;} +| WHILE expression error statement_list END_WHILE + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'DO' after test expression in ST 'WHILE' statement."); yyerrok;} +| WHILE expression DO END_WHILE + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no statement(s) defined after 'DO' in ST 'WHILE' statement."); yynerrs++;} +| WHILE expression DO error END_WHILE + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid statement(s) defined after 'DO' in ST 'WHILE' statement."); yyerrok;} +| WHILE expression error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'WHILE' statement in ST."); yyerrok;} +| WHILE expression DO statement_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'WHILE' statement in ST."); yynerrs++;} +| WHILE error END_WHILE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'WHILE' statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +repeat_statement: + REPEAT statement_list UNTIL expression END_REPEAT + {$$ = new repeat_statement_c($2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| REPEAT UNTIL expression END_REPEAT + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no statement(s) defined after 'REPEAT' in ST 'REPEAT' statement."); yynerrs++;} +| REPEAT error UNTIL expression END_REPEAT + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid statement(s) defined after 'REPEAT' for ST 'REPEAT' statement."); yyerrok;} +| REPEAT statement_list UNTIL END_REPEAT + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no test expression defined after 'UNTIL' in ST 'REPEAT' statement.");} +| REPEAT statement_list UNTIL error END_REPEAT + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid test expression defined after 'UNTIL' in ST 'REPEAT' statement."); yyerrok;} +| REPEAT statement_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'REPEAT' statement in ST."); yynerrs++;} +| REPEAT statement_list UNTIL expression error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'REPEAT' statement in ST."); yyerrok;} +| REPEAT error END_REPEAT + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'REPEAT' statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +exit_statement: + EXIT {$$ = new exit_statement_c(locloc(@$));} +; + + + + + +%% + +#include /* required for printf() */ +#include +#include "../util/symtable.hh" + +/* variables defined in code generated by flex... */ +extern FILE *yyin; +extern int yylineno; +extern tracking_t* current_tracking; + + + + +/*************************************************************************************************/ +/* NOTE: These variables are really parameters we would like the stage2__ function to pass */ +/* to the yyparse() function. However, the yyparse() function is created automatically */ +/* by bison, so we cannot add parameters to this function. The only other */ +/* option is to use global variables! yuck! */ +/*************************************************************************************************/ + +/* A global flag used to tell the parser if overloaded funtions should be allowed. + * The IEC 61131-3 standard allows overloaded funtions in the standard library, + * but disallows them in user code... + * + * In essence, a parameter we would like to pass to the yyparse() function but + * have to do it using a global variable, as the yyparse() prototype is fixed by bison. + */ +bool allow_function_overloading = false; + +/* | [var1_list ','] variable_name '..' */ +/* NOTE: This is an extension to the standard!!! */ +/* In order to be able to handle extensible standard functions + * (i.e. standard functions that may have a variable number of + * input parameters, such as AND(word#33, word#44, word#55, word#66), + * we have extended the acceptable syntax to allow var_name '..' + * in an input variable declaration. + * + * This allows us to parse the declaration of standard + * extensible functions and load their interface definition + * into the abstract syntax tree just like we do to other + * user defined functions. + * This has the advantage that we can later do semantic + * checking of calls to functions (be it a standard or user defined + * function) in (almost) exactly the same way. + * + * Of course, we have a flag that disables this syntax when parsing user + * written code, so we only allow this extra syntax while parsing the + * 'header' file that declares all the standard IEC 61131-3 functions. + */ +bool allow_extensible_function_parameters = false; + +/* A global flag used to tell the parser whether to include the full variable location + * when printing out error messages... + */ +bool full_token_loc; + +/* A pointer to the root of the parsing tree that will be generated + * by bison. + */ +symbol_c *tree_root; + + + +/* The following function is called automatically by bison whenever it comes across + * an error. Unfortunately it calls this function before executing the code that handles + * the error itself, so we cannot print out the correct line numbers of the error location + * over here. + * Our solution is to store the current error message in a global variable, and have all + * error action handlers call the function print_err_msg() after setting the location + * (line number) variable correctly. + */ +const char *current_error_msg; +void yyerror (const char *error_msg) { + current_error_msg = error_msg; +/* fprintf(stderr, "error %d: %s\n", yynerrs // global variable //, error_msg); */ +/* print_include_stack(); */ +} + + +/* ERROR_CHECK_BEGIN */ +bool is_current_syntax_token() { + switch (yychar) { + case ';': + case ',': + case ')': + case ']': + case '+': + case '*': + case '-': + case '/': + case '<': + case '>': + case '=': + case '&': + case OR: + case XOR: + case AND: + case AND2: + case OPER_NE: + case OPER_LE: + case OPER_GE: + case MOD: + case OPER_EXP: + case NOT: + return true; + default: + return false; + } +} +/* ERROR_CHECK_END */ + + +void print_err_msg(int first_line, + int first_column, + const char *first_filename, + long int first_order, + int last_line, + int last_column, + const char *last_filename, + long int last_order, + const char *additional_error_msg) { + + const char *unknown_file = ""; + if (first_filename == NULL) first_filename = unknown_file; + if ( last_filename == NULL) last_filename = unknown_file; + + if (full_token_loc) { + if (first_filename == last_filename) + fprintf(stderr, "%s:%d-%d..%d-%d: error : %s\n", first_filename, first_line, first_column, last_line, last_column, additional_error_msg); + else + fprintf(stderr, "%s:%d-%d..%s:%d-%d: error : %s\n", first_filename, first_line, first_column, last_filename, last_line, last_column, additional_error_msg); + } else { + fprintf(stderr, "%s:%d: error : %s\n", first_filename, first_line, additional_error_msg); + } + //fprintf(stderr, "error %d: %s\n", yynerrs /* a global variable */, additional_error_msg); + print_include_stack(); + //fprintf(stderr, "%s(%d-%d): %s\n", current_filename, first_line, last_line, current_error_msg); +} + + + +/* If function overloading is on, we allow several functions with the same name. + * + * However, to support standard functions, we also allow functions named + * AND, MOD, NOT, OR, XOR, ADD, ... + */ +/* +identifier_c *token_2_identifier_c(char *value, ) { + identifier_c tmp = new identifier_c(value, locloc(@$)); + if (!allow_function_overloading) { + fprintf(stderr, "Function overloading not allowed. Invalid identifier %s\n", ((token_c *)($$))->value); + ERROR; + } + } +} +*/ + +/* convert between an il_operator to a function name */ +/* This a kludge! + * It is required because our language requires more than one + * look ahead token, and bison only works with one! + */ +#define op_2_str(op, str) {\ + op ## _operator_c *ptr = dynamic_cast(il_operator); \ + if (ptr != NULL) name = str; \ +} + +/* NOTE: this code is very ugly and un-eficient, but I (Mario) have many + * more things to worry about right now, so just let it be... + */ +symbol_c *il_operator_c_2_identifier_c(symbol_c *il_operator) { + const char *name = NULL; + identifier_c *res; + + op_2_str(NOT, "NOT"); + + op_2_str(AND, "AND"); + op_2_str(OR, "OR"); + op_2_str(XOR, "XOR"); + op_2_str(ADD, "ADD"); + op_2_str(SUB, "SUB"); + op_2_str(MUL, "MUL"); + op_2_str(DIV, "DIV"); + op_2_str(MOD, "MOD"); + op_2_str(GT, "GT"); + op_2_str(GE, "GE"); + op_2_str(EQ, "EQ"); + op_2_str(LT, "LT"); + op_2_str(LE, "LE"); + op_2_str(NE, "NE"); + + op_2_str(LD, "LD"); + op_2_str(LDN, "LDN"); + op_2_str(ST, "ST"); + op_2_str(STN, "STN"); + + op_2_str(S, "S"); + op_2_str(R, "R"); + op_2_str(S1, "S1"); + op_2_str(R1, "R1"); + + op_2_str(CLK, "CLK"); + op_2_str(CU, "CU"); + op_2_str(CD, "CD"); + op_2_str(PV, "PV"); + op_2_str(IN, "IN"); + op_2_str(PT, "PT"); + + op_2_str(ANDN, "ANDN"); + op_2_str(ORN, "ORN"); + op_2_str(XORN, "XORN"); + + op_2_str(ADD, "ADD"); + op_2_str(SUB, "SUB"); + op_2_str(MUL, "MUL"); + op_2_str(DIV, "DIV"); + + op_2_str(GT, "GT"); + op_2_str(GE, "GE"); + op_2_str(EQ, "EQ"); + op_2_str(LT, "LT"); + op_2_str(LE, "LE"); + op_2_str(NE, "NE"); + + op_2_str(CAL, "CAL"); + op_2_str(CALC, "CALC"); + op_2_str(CALCN, "CALCN"); + op_2_str(RET, "RET"); + op_2_str(RETC, "RETC"); + op_2_str(RETCN, "RETCN"); + op_2_str(JMP, "JMP"); + op_2_str(JMPC, "JMPC"); + op_2_str(JMPCN, "JMPCN"); + + if (name == NULL) + ERROR; + + res = new identifier_c(strdup(name), + il_operator->first_line, + il_operator->first_column, + il_operator->first_file, + il_operator->first_order, + il_operator->last_line, + il_operator->last_column, + il_operator->last_file, + il_operator->last_order + ); + free(il_operator); + return res; +} + + +#include "standard_function_names.c" + +const char *standard_function_block_names[] = { +// 2.5.2.3.1 Bistable elements +// Table 34 - Standard bistable function blocks +"SR","RS", +// 2.5.2.3.2 Edge detection +// Table 35 - Standard edge detection function blocks +"R_TRIG","F_TRIG", +// 2.5.2.3.3 Counters +// Table 36 - Standard counter function blocks +"CTU","CTU_DINT","CTU_LINT","CTU_UDINT","CTU_ULINT", +"CTD","CTD_DINT","CTD_LINT","CTD_UDINT","CTD_ULINT", +"CTUD","CTUD_DINT","CTUD_LINT","CTUD_ULINT", +// 2.5.2.3.4 Timers +// Table 37 - Standard timer function blocks +"TP","TON","TOF", +/* end of array marker! Do not remove! */ +NULL +}; + + +#define LIBFILE "ieclib.txt" +#define DEF_LIBFILENAME LIBDIRECTORY "/" LIBFILE + +extern const char *INCLUDE_DIRECTORIES[]; + + + +int stage2__(const char *filename, + const char *includedir, /* Include directory, where included files will be searched for... */ + symbol_c **tree_root_ref, + bool full_token_loc_ /* error messages specify full token location */ + ) { + + FILE *in_file = NULL, *lib_file = NULL; + char *libfilename = NULL; + + if((in_file = fopen(filename, "r")) == NULL) { + char *errmsg = strdup2("Error opening main file ", filename); + perror(errmsg); + free(errmsg); + return -1; + } + + if (includedir != NULL) { + INCLUDE_DIRECTORIES[0] = includedir; + } + if ((libfilename = strdup3(INCLUDE_DIRECTORIES[0], "/", LIBFILE)) == NULL) { + fprintf (stderr, "Out of memory. Bailing out!\n"); + return -1; + } + + if((lib_file = fopen(libfilename, "r")) == NULL) { + char *errmsg = strdup2("Error opening library file ", libfilename); + perror(errmsg); + free(errmsg); + } + + if (lib_file == NULL) { + /* we give up... */ + free(libfilename); + fclose(in_file); + return -1; + } + + /* first parse the standard library file... */ + /* + #if YYDEBUG + yydebug = 1; + #endif + */ + yyin = lib_file; + allow_function_overloading = true; + allow_extensible_function_parameters = true; + full_token_loc = full_token_loc_; + current_filename = libfilename; + current_tracking = GetNewTracking(yyin); + if (yyparse() != 0) + ERROR; + + if (yynerrs > 0) { + fprintf (stderr, "\nFound %d error(s) in %s. Bailing out!\n", yynerrs /* global variable */, libfilename); + ERROR; + } + free(libfilename); + fclose(lib_file); + + /* if by any chance the library is not complete, we + * now add the missing reserved keywords to the list!!! + */ + for(int i = 0; standard_function_block_names[i] != NULL; i++) + if (library_element_symtable.find_value(standard_function_block_names[i]) == + library_element_symtable.end_value()) + library_element_symtable.insert(standard_function_block_names[i], standard_function_block_name_token); + + + /* now parse the input file... */ + #if YYDEBUG + yydebug = 1; + #endif + yyin = in_file; + allow_function_overloading = false; + allow_extensible_function_parameters = false; + full_token_loc = full_token_loc_; + current_filename = filename; + current_tracking = GetNewTracking(yyin); + {int res; + if ((res = yyparse()) != 0) { + fprintf (stderr, "\nParsing failed because of too many consecutive syntax errors. Bailing out!\n"); + exit(EXIT_FAILURE); + } + } + + if (yynerrs > 0) { + fprintf (stderr, "\nFound %d error(s). Bailing out!\n", yynerrs /* global variable */); + exit(EXIT_FAILURE); + } + + if (tree_root_ref != NULL) + *tree_root_ref = tree_root; + + fclose(in_file); + return 0; +} + + + diff -r 17bffb57a8c5 -r 0f24db96b519 stage1_2/iec_flex.ll --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage1_2/iec_flex.ll Fri Aug 19 17:33:57 2011 +0100 @@ -0,0 +1,1719 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt) + * + * 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 . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +/* + * An IEC 61131-3 compiler. + * + * Based on the + * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) + * + */ + +/* + * Stage 1 + * ======= + * + * This file contains the lexical tokens definitions, from which + * the flex utility will generate a lexical parser function. + */ + + + + +/*****************************/ +/* Lexical Parser Options... */ +/*****************************/ + +/* The lexical analyser will never work in interactive mode, + * i.e., it will only process programs saved to files, and never + * programs being written inter-actively by the user. + * This option saves the resulting parser from calling the + * isatty() function, that seems to be generating some compile + * errors under some (older?) versions of flex. + */ +%option never-interactive + +/* Have the lexical analyser use a 'char *yytext' instead of an + * array of char 'char yytext[??]' to store the lexical token. + */ +%pointer + + +/* Have the lexical analyser ignore the case of letters. + * This will occur for all the tokens and keywords, but + * the resulting text handed up to the syntax parser + * will not be changed, and keep the original case + * of the letters in the input file. + */ +%option case-insensitive + +/* Have the generated lexical analyser keep track of the + * line number it is currently analysing. + * This is used to pass up to the syntax parser + * the number of the line on which the current + * token was found. It will enable the syntax parser + * to generate more informatve error messages... + */ +%option yylineno + +/* required for the use of the yy_pop_state() and + * yy_push_state() functions + */ +%option stack + +/* The '%option stack' also requests the inclusion of + * the yy_top_state(), however this function is not + * currently being used. This means that the compiler + * is complaining about the existance of this function. + * The following option removes the yy_top_state() + * function from the resulting c code, so the compiler + * no longer complains. + */ +%option noyy_top_state + +/* We will not be using unput() in our flex code... */ +%option nounput + +/**************************************************/ +/* External Variable and Function declarations... */ +/**************************************************/ + + +%{ +/* Define TEST_MAIN to include a main() function. + * Useful for testing the parser generated by flex. + */ +/* +#define TEST_MAIN +*/ +/* If lexical parser is compiled by itself, we need to define the following + * constant to some string. Under normal circumstances LIBDIRECTORY is set + * in the syntax parser header file... + */ +#ifdef TEST_MAIN +#define DEFAULT_LIBDIR "just_testing" +#endif + + + +/* Required for strdup() */ +#include + +/* Required only for the declaration of abstract syntax classes + * (class symbol_c; class token_c; class list_c;) + * These will not be used in flex, but the token type union defined + * in iec_bison.h contains pointers to these classes, so we must include + * it here. + */ +#include "../absyntax/absyntax.hh" + + +/* iec_bison.h is generated by bison. + * Contains the definition of the token constants, and the + * token value type YYSTYPE (in our case, a 'const char *') + */ +#include "iec_bison.h" +#include "stage1_2_priv.hh" + + +/* Variable defined by the bison parser, + * where the value of the tokens will be stored + */ +extern YYSTYPE yylval; + +/* The name of the file currently being parsed... + * This variable is declared and read from the code generated by bison! + * Note that flex accesses and updates this global variable + * apropriately whenever it comes across an (*#include *) + * directive... + */ +/* + NOTE: already defined in iec_bison.h +extern const char *current_filename; +*/ + + +/* We will not be using unput() in our flex code... */ +/* NOTE: it seems that this #define is no longer needed, It has been + * replaced by %option nounput. + * Should we simply delete it? + * For now leave it in, in case someone is using an old version of flex. + * In any case, the most harm that can result in a warning message + * when compiling iec.flex.c: + * warning: ‘void yyunput(int, char*)’ defined but not used + */ +#define YY_NO_UNPUT + +/* Variable defined by the bison parser. + * It must be initialised with the location + * of the token being parsed. + * This is only needed if we want to keep + * track of the locations, in order to give + * more meaningful error messages! + */ +extern YYLTYPE yylloc; + +#define YY_INPUT(buf,result,max_size) {\ + result = GetNextChar(buf, max_size);\ + if ( result <= 0 )\ + result = YY_NULL;\ + } + + +/* A counter to track the order by which each token is processed. + * NOTE: This counter is not exactly linear (i.e., it does not get incremented by 1 for each token). + * i.e.. it may get incremented by more than one between two consecutive tokens. + * This is due to the fact that the counter gets incremented every 'user action' in flex, + * however not every user action will result in a token being passed to bison. + * Nevertheless this is still OK, as we are only interested in the relative + * ordering of tokens... + */ +static long int current_order = 0; + + +/* Macro that is executed for every action. + * We use it to pass the location of the token + * back to the bison parser... + */ +#define YY_USER_ACTION {\ + yylloc.first_line = current_tracking->lineNumber; \ + yylloc.first_column = current_tracking->currentTokenStart; \ + yylloc.first_file = current_filename; \ + yylloc.first_order = current_order; \ + yylloc.last_line = current_tracking->lineNumber; \ + yylloc.last_column = current_tracking->currentChar - 1; \ + yylloc.last_file = current_filename; \ + yylloc.last_order = current_order; \ + current_tracking->currentTokenStart = current_tracking->currentChar; \ + current_order++; \ + } + + +/* Since this lexical parser we defined only works in ASCII based + * systems, we might as well make sure it is being compiled on + * one... + * Lets check a few random characters... + */ +#if (('a' != 0x61) || ('A' != 0x41) || ('z' != 0x7A) || ('Z' != 0x5A) || \ + ('0' != 0x30) || ('9' != 0x39) || ('(' != 0x28) || ('[' != 0x5B)) +#error This lexical analyser is not portable to a non ASCII based system. +#endif + + +/* Function only called from within flex, but defined + * in iec.y! + * We declare it here... + * + * Search for a symbol in either of the two symbol tables + * and return the token id of the first symbol found. + * Searches first in the variables, and only if not found + * does it continue searching in the library elements + */ +//token_id_t get_identifier_token(const char *identifier_str); +int get_identifier_token(const char *identifier_str); +%} + + +/***************************************************/ +/* Forward Declaration of functions defined later. */ +/***************************************************/ + +%{ +/* return all the text in the current token back to the input stream. */ +void unput_text(unsigned int n); +%} + + + +/****************************/ +/* Lexical Parser States... */ +/****************************/ + +/* NOTE: Our psrser can parse st or il code, intermixed + * within the same file. + * With IL we come across the issue of the EOL (end of line) token. + * ST, and the declaration parts of IL do not use this token! + * If the lexical analyser were to issue this token during ST + * language parsing, or during the declaration of data types, + * function headers, etc. in IL, the syntax parser would crash. + * + * We can solve this issue using one of three methods: + * (1) Augment all the syntax that does not accept the EOL + * token to simply ignore it. This makes the syntax + * definition (in iec.y) very cluttered! + * (2) Let the lexical parser figure out which language + * it is parsing, and decide whether or not to issue + * the EOL token. This requires the lexical parser + * to have knowledge of the syntax!, making for a poor + * overall organisation of the code. It would also make it + * very difficult to understand the lexical parser as it + * would use several states, and a state machine to transition + * between the states. The state transitions would be + * intermingled with the lexical parser defintion! + * (3) Use a mixture of (1) and (2). The lexical analyser + * merely distinguishes between function headers and function + * bodies, but no longer makes a distinction between il and + * st language bodies. When parsing a body, it will return + * the EOL token. In other states '\n' will be ignored as + * whitespace. + * The ST language syntax has been augmented in the syntax + * parser configuration to ignore any EOL tokens that it may + * come across! + * This option has both drawbacks of option (1) and (2), but + * much less intensely. + * The syntax that gets cluttered is limited to the ST statements + * (which is rather limited, compared to the function headers and + * data type declarations, etc...), while the state machine in + * the lexical parser becomes very simple. All state transitions + * can be handled within the lexical parser by itself, and can be + * easily identified. Thus knowledge of the syntax required by + * the lexical parser is very limited! + * + * Amazingly enough, I (Mario) got to implement option (3) + * at first, requiring two basic states, decl and body. + * The lexical parser will enter the body state when + * it is parsing the body of a function/program/function block. The + * state transition is done when we find a VAR_END that is not followed + * by a VAR! This is the syntax knowledge that gets included in the + * lexical analyser with this option! + * Unfortunately, getting the st syntax parser to ignore EOL anywhere + * where they might appear leads to conflicts. This is due to the fact + * that the syntax parser uses the single look-ahead token to remove + * possible conflicts. When we insert a possible EOL, the single + * look ahead token becomes the EOL, which means the potential conflicts + * could no longer be resolved. + * Removing these conflicts would make the st syntax parser very convoluted, + * and adding the extraneous EOL would make it very cluttered. + * This option was therefore dropped in favour of another! + * + * I ended up implementing (2). Unfortunately the lexical analyser can + * not easily distinguish between il and st code, since function + * calls in il are very similar to function block calls in st. + * We therefore use an extra 'body' state. When the lexical parser + * finds that last END_VAR, it enters the body state. This state + * must figure out what language is being parsed from the first few + * tokens, and switch to the correct state (st, il or sfc) according to the + * language. This means that we insert quite a bit of knowledge of the + * syntax of the languages into the lexical parser. This is ugly, but it + * works, and at least it is possible to keep all the state changes together + * to make it easier to remove them later on if need be. + * Once the language being parsed has been identified, + * the body state returns any matched text back to the buffer with unput(), + * to be later matched correctly by the apropriate language parser (st, il or sfc). + * + * Aditionally, in sfc state it may further recursively enter the body state + * once again. This is because an sfc body may contain ACTIONS, which are then + * written in one of the three languages (ST, IL or SFC), so once again we need + * to figure out which language the ACTION in the SFC was written in. We already + * ahve all that done in the body state, so we recursively transition to the body + * state once again. + * Note that in this case, when coming out of the st/il state (whichever language + * the action was written in) the sfc state will become active again. This is done by + * pushing and poping the previously active state! + * + * The sfc_qualifier_state is required because when parsing actions within an + * sfc, we will be expecting action qualifiers (N, P, R, S, DS, SD, ...). In order + * to bison to work correctly, these qualifiers must be returned as tokens. However, + * these tokens are not reserved keywords, which means it should be possible to + * define variables/functions/FBs with any of these names (including + * S and R which are special because they are also IL operators). So, when we are not + * expecting any action qualifiers, flex does not return these tokens, and is free + * to interpret them as previously defined variables/functions/... as the case may be. + * + * The state machine has 7 possible states (INITIAL, config, decl, body, st, il, sfc) + * Possible state changes are: + * INITIAL -> goto(decl_state) + * (when a FUNCTION, FUNCTION_BLOCK, or PROGRAM is found, + * and followed by a VAR declaration) + * INITIAL -> goto(body_state) + * (when a FUNCTION, FUNCTION_BLOCK, or PROGRAM is found, + * and _not_ followed by a VAR declaration) + * (This transition is actually commented out, since the syntax + * does not allow the declaration of functions, FBs, or programs + * without any VAR declaration!) + * INITIAL -> goto(config_state) + * (when a CONFIGURATION is found) + * decl_state -> push(decl_state); goto(body_state) + * (when the last END_VAR is found, i.e. the function body starts) + * decl_state -> push(decl_state); goto(sfc_state) + * (when it figures out it is parsing sfc language) + * body_state -> goto(st_state) + * (when it figures out it is parsing st language) + * body_state -> goto(il_state) + * (when it figures out it is parsing il language) + * st_state -> pop() + * (when a END_FUNCTION, END_FUNCTION_BLOCK, END_PROGRAM, + * END_ACTION or END_TRANSITION is found) + * il_state -> pop() + * (when a END_FUNCTION, END_FUNCTION_BLOCK, END_PROGRAM, + * END_ACTION or END_TRANSITION is found) + * decl_state -> goto(INITIAL) + * (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found) + * sfc_state -> goto(INITIAL) + * (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found) + * config_state -> goto(INITIAL) + * (when a END_CONFIGURATION is found) + * sfc_state -> push(sfc_state); goto(body_state) + * (when parsing an action. This transition is requested by bison) + * sfc_state -> push(sfc_state); goto(sfc_qualifier_state) + * (when expecting an action qualifier. This transition is requested by bison) + * sfc_qualifier_state -> pop() + * (when no longer expecting an action qualifier. This transition is requested by bison) + * config_state -> push(config_state); goto(task_init_state) + * (when parsing a task initialisation. This transition is requested by bison) + * task_init_state -> pop() + * (when no longer parsing task initialisation parameters. This transition is requested by bison) + * + */ + + +/* we are parsing a configuration. */ +%s config_state + +/* Inside a configuration, we are parsing a task initialisation parameters */ +/* This means that PRIORITY, SINGLE and INTERVAL must be handled as + * tokens, and not as possible identifiers. Note that the above words + * are not keywords. + */ +%s task_init_state + +/* we are parsing a function, program or function block declaration */ +%s decl_state + +/* we will be parsing a function body. Whether il/st is remains unknown */ +%x body_state + +/* we are parsing il code -> flex must return the EOL tokens! */ +%s il_state + +/* we are parsing st code -> flex must not return the EOL tokens! */ +%s st_state + +/* we are parsing sfc code -> flex must not return the EOL tokens! */ +%s sfc_state + +/* we are parsing sfc code, and expecting an action qualifier. */ +%s sfc_qualifier_state + +/* we are parsing sfc code, and expecting the priority token. */ +%s sfc_priority_state + + + + +/*******************/ +/* File #include's */ +/*******************/ + +/* We extend the IEC 61131-3 standard syntax to allow inclusion + * of other files, using the IEC 61131-3 pragma directive... + * The accepted syntax is: + * {#include ""} + */ + +/* the "include" states are used for picking up the name of an include file */ +%x include_beg +%x include_filename +%x include_end + + +file_include_pragma_filename [^\"]* +file_include_pragma_beg "{#include"{st_whitespace_only}\" +file_include_pragma_end \"{st_whitespace_only}"}" +file_include_pragma {file_include_pragma_beg}{file_include_pragma_filename}{file_include_pragma_end} + + +%{ +#define MAX_INCLUDE_DEPTH 16 + +typedef struct { + YY_BUFFER_STATE buffer_state; + tracking_t* env; + const char *filename; + } include_stack_t; + +tracking_t* current_tracking; +include_stack_t include_stack[MAX_INCLUDE_DEPTH]; +int include_stack_ptr = 0; + +const char *INCLUDE_DIRECTORIES[] = { + DEFAULT_LIBDIR, + ".", + "/lib", + "/usr/lib", + "/usr/lib/iec", + NULL /* must end with NULL!! */ + }; + +%} + + + +/*****************************/ +/* Prelimenary constructs... */ +/*****************************/ + +/* In order to allow the declaration of POU prototypes (Function, FB, Program, ...), + * especially the prototypes of Functions and FBs defined in the standard + * (i.e. standard functions and FBs), we extend the IEC 61131-3 standard syntax + * with two pragmas to indicate that the code is to be parsed (going through the + * lexical, syntactical, and semantic analysers), but no code is to be generated. + * + * The accepted syntax is: + * {no_code_generation begin} + * ... prototypes ... + * {no_code_generation end} + * + * When parsing these prototypes the abstract syntax tree will be populated as usual, + * allowing the semantic analyser to correctly analyse the semantics of calls to these + * functions/FBs. However, stage4 will simply ignore all IEC61131-3 code + * between the above two pragmas. + */ + +disable_code_generation_pragma "{disable code generation}" +enable_code_generation_pragma "{enable code generation}" + + +/* Any other pragma... */ + +pragma "{"[^}]*"}" + +/* NOTE: this seemingly unnecessary complex definition is required + * to be able to eat up comments such as: + * '(* Testing... ! ***** ******)' + * without using the trailing context command in flex (/{context}) + * since {comment} itself will later be used with + * trailing context ({comment}/{context}) + */ +not_asterisk [^*] +not_close_parenthesis_nor_asterisk [^*)] +asterisk "*" +comment_text {not_asterisk}|(({asterisk}+){not_close_parenthesis_nor_asterisk}) + +comment "(*"({comment_text}*)({asterisk}+)")" + + +/* +3.1 Whitespace + (NOTE: Whitespace IS clearly defined, to include newline!!! See section 2.1.4!!!) + No definition of whitespace is given, in other words, the characters that may be used to seperate language tokens are not pecisely defined. One may nevertheless make an inteligent guess of using the space (' '), and other characters also commonly considered whitespace in other programming languages (horizontal tab, vertical tab, form feed, etc.). + The main question is whether the newline character should be considered whitespace. IL language statements use an EOL token (End Of Line) to distinguish between some language constructs. The EOL token itself is openly defined as "normally consist[ing] of the 'paragraph separator' ", leaving the final choice open to each implemention. If we choose the newline character to represent the EOL token, it may then not be considered whitespace. + On the other hand, some examples that come in a non-normative annex of the specification allow function declarations to span multiple3.1 Whitespace + (NOTE: Whitespace IS clearly defined, to include newline!!! See section 2.1.4!!!) + No definition of whitespace is given, in other words, the characters that may be used to seperate language tokens are not pecisely defined. One may nevertheless make an inteligent guess of using the space (' '), and other characters also commonly considered whitespace in other programming languages (horizontal tab, vertical tab, form feed, etc.). + The main question is whether the newline character should be considered whitespace. IL language statements use an EOL token (End Of Line) to distinguish between some language constructs. The EOL token itself is openly defined as "normally consist[ing] of the 'paragraph separator' ", leaving the final choice open to each implemention. If we choose the newline character to represent the EOL token, it may then not be considered whitespace. + On the other hand, some examples that come in a non-normative annex of the specification allow function declarations to span multiple lines, which means that the newline character is being considered as whitespace. + Our implementation works around this issue by including the new line character in the whitespace while parsing function declarations and the ST language, and parsing it as the EOL token only while parsing IL language statements. This requires the use of a state machine in the lexical parser that needs at least some knowledge of the syntax itself. +*/ +/* NOTE: Our definition of whitespace will only work in ASCII! + * + * Since the IL language needs to know the location of newline + * (token EOL -> '\n' ), we need one definition of whitespace + * for each language... + */ +/* + * NOTE: we cannot use + * st_whitespace [:space:]* + * since we use {st_whitespace} as trailing context. In our case + * this would not constitute "dangerous trailing context", but the + * lexical generator (i.e. flex) does not know this (since it does + * not know which characters belong to the set [:space:]), and will + * generate a "dangerous trailing context" warning! + * We use this alternative just to stop the flex utility from + * generating the invalid (in this case) warning... + */ + +st_whitespace_only [ \f\n\r\t\v]* +il_whitespace_only [ \f\r\t\v]* + +st_whitespace_text {st_whitespace_only}|{comment}|{pragma} +il_whitespace_text {il_whitespace_only}|{comment}|{pragma} + +st_whitespace {st_whitespace_text}* +il_whitespace {il_whitespace_text}* + +st_whitespace_text_no_pragma {st_whitespace_only}|{comment} +il_whitespace_text_no_pragma {il_whitespace_only}|{comment} + +st_whitespace_no_pragma {st_whitespace_text_no_pragma}* +il_whitespace_no_pragma {il_whitespace_text_no_pragma}* + +qualified_identifier {identifier}(\.{identifier})* + + + +/*****************************************/ +/* B.1.1 Letters, digits and identifiers */ +/*****************************************/ +/* NOTE: The following definitions only work if the host computer + * is using the ASCII maping. For e.g., with EBCDIC [A-Z] + * contains non-alphabetic characters! + * The correct way of doing it would be to use + * the [:upper:] etc... definitions. + * + * Unfortunately, further on we need all printable + * characters (i.e. [:print:]), but excluding '$'. + * Flex does not allow sets to be composed by excluding + * elements. Sets may only be constructed by adding new + * elements, which means that we have to revert to + * [\x20\x21\x23\x25\x26\x28-x7E] for the definition + * of the printable characters with the required exceptions. + * The above also implies the use of ASCII, but now we have + * no way to work around it| + * + * The conclusion is that our parser is limited to ASCII + * based host computers!! + */ +letter [A-Za-z] +digit [0-9] +octal_digit [0-7] +hex_digit {digit}|[A-F] +identifier ({letter}|(_({letter}|{digit})))((_?({letter}|{digit}))*) + +/*******************/ +/* B.1.2 Constants */ +/*******************/ + +/******************************/ +/* B.1.2.1 Numeric literals */ +/******************************/ +integer {digit}((_?{digit})*) +binary_integer 2#{bit}((_?{bit})*) +bit [0-1] +octal_integer 8#{octal_digit}((_?{octal_digit})*) +hex_integer 16#{hex_digit}((_?{hex_digit})*) +exponent [Ee]([+-]?){integer} +/* The correct definition for real would be: + * real {integer}\.{integer}({exponent}?) + * + * Unfortunately, the spec also defines fixed_point (B 1.2.3.1) as: + * fixed_point {integer}\.{integer} + * + * This means that {integer}\.{integer} could be interpreted + * as either a fixed_point or a real. + * I have opted to interpret {integer}\.{integer} as a fixed_point. + * In order to do this, the definition of real has been changed to: + * real {integer}\.{integer}{exponent} + * + * This means that the syntax parser now needs to define a real to be + * either a real_token or a fixed_point_token! + */ +real {integer}\.{integer}{exponent} + + +/*******************************/ +/* B.1.2.2 Character Strings */ +/*******************************/ +/* +common_character_representation := + +|'$$' +|'$L'|'$N'|'$P'|'$R'|'$T' +|'$l'|'$n'|'$p'|'$r'|'$t' + +NOTE: $ = 0x24 + " = 0x22 + ' = 0x27 + + printable chars in ASCII: 0x20-0x7E +*/ + +esc_char_u $L|$N|$P|$R|$T +esc_char_l $l|$n|$p|$r|$t +esc_char $$|{esc_char_u}|{esc_char_l} +double_byte_char (${hex_digit}{hex_digit}{hex_digit}{hex_digit}) +single_byte_char (${hex_digit}{hex_digit}) + +/* WARNING: + * This definition is only valid in ASCII... + * + * Flex includes the function print_char() that defines + * all printable characters portably (i.e. whatever character + * encoding is currently being used , ASCII, EBCDIC, etc...) + * Unfortunately, we cannot generate the definition of + * common_character_representation portably, since flex + * does not allow definition of sets by subtracting + * elements in one set from another set. + * This means we must build up the defintion of + * common_character_representation using only set addition, + * which leaves us with the only choice of defining the + * characters non-portably... + */ +common_character_representation [\x20\x21\x23\x25\x26\x28-\x7E]|{esc_char} +double_byte_character_representation $\"|'|{double_byte_char}|{common_character_representation} +single_byte_character_representation $'|\"|{single_byte_char}|{common_character_representation} + + +double_byte_character_string \"({double_byte_character_representation}*)\" +single_byte_character_string '({single_byte_character_representation}*)' + + +/************************/ +/* B 1.2.3.1 - Duration */ +/************************/ +fixed_point {integer}\.{integer} + +fixed_point_d {fixed_point}d +integer_d {integer}d + +fixed_point_h {fixed_point}h +integer_h {integer}h + +fixed_point_m {fixed_point}m +integer_m {integer}m + +fixed_point_s {fixed_point}s +integer_s {integer}s + +fixed_point_ms {fixed_point}ms +integer_ms {integer}ms + + +/********************************************/ +/* B.1.4.1 Directly Represented Variables */ +/********************************************/ +/* The correct definition, if the standard were to be followed... */ + +location_prefix [IQM] +size_prefix [XBWDL] +direct_variable_standard %{location_prefix}({size_prefix}?){integer}((.{integer})*) + + +/* For the MatPLC, we will accept % + * as a direct variable, this being mapped onto the MatPLC point + * named + */ +/* TODO: we should not restrict it to only the accepted syntax + * of as specified by the standard. MatPLC point names + * have a more permissive syntax. + * + * e.g. "P__234" + * Is a valid MatPLC point name, but not a valid !! + * The same happens with names such as "333", "349+23", etc... + * How can we handle these more expressive names in our case? + * Remember that some direct variable may remain anonymous, with + * declarations such as: + * VAR + * AT %I3 : BYTE := 255; + * END_VAR + * in which case we are currently using "%I3" as the variable + * name. + */ +direct_variable_matplc %{identifier} + +direct_variable {direct_variable_standard}|{direct_variable_matplc} + +/******************************************/ +/* B 1.4.3 - Declaration & Initialisation */ +/******************************************/ +incompl_location %[IQM]\* + + + + +%% + /* fprintf(stderr, "flex: state %d\n", YY_START); */ + + /*****************************************************/ + /*****************************************************/ + /*****************************************************/ + /***** *****/ + /***** *****/ + /***** F I R S T T H I N G S F I R S T *****/ + /***** *****/ + /***** *****/ + /*****************************************************/ + /*****************************************************/ + /*****************************************************/ + + /***********************************************************/ + /* Handle requests sent by bison for flex to change state. */ + /***********************************************************/ + if (get_goto_body_state()) { + yy_push_state(body_state); + rst_goto_body_state(); + } + + if (get_goto_sfc_qualifier_state()) { + yy_push_state(sfc_qualifier_state); + rst_goto_sfc_qualifier_state(); + } + + if (get_goto_sfc_priority_state()) { + yy_push_state(sfc_priority_state); + rst_goto_sfc_priority_state(); + } + + if (get_goto_task_init_state()) { + yy_push_state(task_init_state); + rst_goto_task_init_state(); + } + + if (get_pop_state()) { + yy_pop_state(); + rst_pop_state(); + } + + /***************************/ + /* Handle the pragmas! */ + /***************************/ + + /* We start off by searching for the pragmas we handle in the lexical parser. */ +{file_include_pragma} unput_text(0); yy_push_state(include_beg); + + /* Pragmas sent to syntax analyser (bison) */ +{disable_code_generation_pragma} return disable_code_generation_pragma_token; +{enable_code_generation_pragma} return enable_code_generation_pragma_token; +{disable_code_generation_pragma} return disable_code_generation_pragma_token; +{enable_code_generation_pragma} return enable_code_generation_pragma_token; + + /* Any other pragma we find, we just pass it up to the syntax parser... */ + /* Note that the state is exclusive, so we have to include it here too. */ +{pragma} {/* return the pragmma without the enclosing '{' and '}' */ + yytext[strlen(yytext)-1] = '\0'; + yylval.ID=strdup(yytext+1); + return pragma_token; + } +{pragma} {/* return the pragmma without the enclosing '{' and '}' */ + yytext[strlen(yytext)-1] = '\0'; + yylval.ID=strdup(yytext+1); + return pragma_token; + } + + + /*********************************/ + /* Handle the file includes! */ + /*********************************/ +{file_include_pragma_beg} BEGIN(include_filename); + +{file_include_pragma_filename} { + /* got the include file name */ + int i; + + if (include_stack_ptr >= MAX_INCLUDE_DEPTH) { + fprintf(stderr, "Includes nested too deeply\n"); + exit( 1 ); + } + include_stack[include_stack_ptr].buffer_state = YY_CURRENT_BUFFER; + include_stack[include_stack_ptr].env = current_tracking; + include_stack[include_stack_ptr].filename = current_filename; + + for (i = 0, yyin = NULL; (INCLUDE_DIRECTORIES[i] != NULL) && (yyin == NULL); i++) { + char *full_name = strdup3(INCLUDE_DIRECTORIES[i], "/", yytext); + if (full_name == NULL) { + fprintf(stderr, "Out of memory!\n"); + exit( 1 ); + } + yyin = fopen(full_name, "r"); + free(full_name); + } + + if (!yyin) { + fprintf(stderr, "Error opening included file %s\n", yytext); + exit( 1 ); + } + + current_filename = strdup(yytext); + current_tracking = GetNewTracking(yyin); + include_stack_ptr++; + + /* switch input buffer to new file... */ + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); + /* switch to whatever state was active before the include file */ + yy_pop_state(); + /* now process the new file... */ + } + + +<> { /* NOTE: We must not change the value of include_stack_ptr + * just yet. We must only decrement it if we are NOT + * at the end of the main file. + * If we have finished parsing the main file, then we + * must leave include_stack_ptr at 0, in case the + * parser is called once again with a new file. + * (In fact, we currently do just that!) + */ + free(current_tracking); + if (include_stack_ptr == 0) { + /* yyterminate() terminates the scanner and returns a 0 to the + * scanner's caller, indicating "all done". + * + * Our syntax parser (written with bison) has the token + * END_OF_INPUT associated to the value 0, so even though + * we don't explicitly return the token END_OF_INPUT + * calling yyterminate() is equivalent to doing that. + */ + yyterminate(); + } + else { + --include_stack_ptr; + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer((include_stack[include_stack_ptr]).buffer_state); + current_tracking = include_stack[include_stack_ptr].env; + /* removing constness of char *. This is safe actually, + * since the only real const char * that is stored on the stack is + * the first one (i.e. the one that gets stored in include_stack[0], + * which is never free'd! + */ + /* NOTE: We do __NOT__ free the malloc()'d memory since + * pointers to this filename will be kept by many objects + * in the abstract syntax tree. + * This will later be used to provide correct error + * messages during semantic analysis (stage 3) + */ + /* free((char *)current_filename); */ + current_filename = include_stack[include_stack_ptr].filename; + yy_push_state(include_end); + } + } + +{file_include_pragma_end} yy_pop_state(); + + + /*********************************/ + /* Handle all the state changes! */ + /*********************************/ + + /* INITIAL -> decl_state */ +{ + /* NOTE: how about functions that do not declare variables, and go directly to the body_state??? + * - According to Section 2.5.1.3 (Function Declaration), item 2 in the list, a FUNCTION + * must have at least one input argument, so a correct declaration will have at least + * one VAR_INPUT ... VAR_END construct! + * - According to Section 2.5.2.2 (Function Block Declaration), a FUNCTION_BLOCK + * must have at least one input argument, so a correct declaration will have at least + * one VAR_INPUT ... VAR_END construct! + * - According to Section 2.5.3 (Programs), a PROGRAM must have at least one input + * argument, so a correct declaration will have at least one VAR_INPUT ... VAR_END + * construct! + * + * All the above means that we needn't worry about PROGRAMs, FUNCTIONs or + * FUNCTION_BLOCKs that do not have at least one VAR_END before the body_state. + * If the code has an error, and no VAR_END before the body, we will simply + * continue in the state, untill the end of the FUNCTION, FUNCTION_BLOCK + * or PROGAM. + */ +FUNCTION BEGIN(decl_state); return FUNCTION; +FUNCTION_BLOCK BEGIN(decl_state); return FUNCTION_BLOCK; +PROGRAM BEGIN(decl_state); return PROGRAM; +CONFIGURATION BEGIN(config_state); return CONFIGURATION; +} + + /* INITIAL -> body_state */ + /* required if the function, program, etc.. has no VAR block! */ + /* We comment it out since the standard does not allow this. */ + /* NOTE: Even if we were to include the following code, it */ + /* would have no effect whatsoever since the above */ + /* rules will take precendence! */ + /* +{ +FUNCTION BEGIN(body_state); return FUNCTION; +FUNCTION_BLOCK BEGIN(body_state); return FUNCTION_BLOCK; +PROGRAM BEGIN(body_state); return PROGRAM; +} + */ + + /* decl_state -> (body_state | sfc_state) */ +{ +END_VAR{st_whitespace}VAR {unput_text(strlen("END_VAR")); + return END_VAR; + } +END_VAR{st_whitespace}INITIAL_STEP {unput_text(strlen("END_VAR")); + yy_push_state(sfc_state); + return END_VAR; + } +END_VAR{st_whitespace} {unput_text(strlen("END_VAR")); + cmd_goto_body_state(); + return END_VAR; + } +} + + /* body_state -> (il_state | st_state) */ +{ +{st_whitespace_no_pragma} /* Eat any whitespace */ +{qualified_identifier}{st_whitespace}":=" unput_text(0); BEGIN(st_state); +{direct_variable_standard}{st_whitespace}":=" unput_text(0); BEGIN(st_state); +{qualified_identifier}"[" unput_text(0); BEGIN(st_state); + +RETURN unput_text(0); BEGIN(st_state); +IF unput_text(0); BEGIN(st_state); +CASE unput_text(0); BEGIN(st_state); +FOR unput_text(0); BEGIN(st_state); +WHILE unput_text(0); BEGIN(st_state); +REPEAT unput_text(0); BEGIN(st_state); +EXIT unput_text(0); BEGIN(st_state); + + /* ':=' occurs only in transitions, and not Function or FB bodies! */ +:= unput_text(0); BEGIN(st_state); + + /* Hopefully, the above rules (along with the last one), + * used to distinguish ST from IL, are + * enough to handle all ocurrences. However, if + * there is some situation where the compiler is getting confused, + * we add the following rule to detect 'label:' in IL code. This will + * allow the user to insert a label right at the beginning (which + * will probably not be used further by his code) simply as a way + * to force the compiler to interpret his code as IL code. + */ +{identifier}{st_whitespace}":"{st_whitespace} unput_text(0); BEGIN(il_state); + +{identifier} {int token = get_identifier_token(yytext); + if (token == prev_declared_fb_name_token) { + /* the code has a call to a function block */ + /* NOTE: if we ever decide to allow the user to use IL operator tokens + * (LD, ST, ...) as identifiers for variable names (including + * function block instances), then the above inference/conclusion + * may be incorrect, and this condition may have to be changed! + */ + BEGIN(st_state); + } else { + BEGIN(il_state); + } + unput_text(0); + } + +. unput_text(0); BEGIN(il_state); +} /* end of body_state lexical parser */ + + /* (il_state | st_state) -> $previous_state (decl_state or sfc_state) */ +{ +END_FUNCTION yy_pop_state(); unput_text(0); +END_FUNCTION_BLOCK yy_pop_state(); unput_text(0); +END_PROGRAM yy_pop_state(); unput_text(0); +END_TRANSITION yy_pop_state(); unput_text(0); +END_ACTION yy_pop_state(); unput_text(0); +} + + /* sfc_state -> INITIAL */ +{ +END_FUNCTION yy_pop_state(); unput_text(0); +END_FUNCTION_BLOCK yy_pop_state(); unput_text(0); +END_PROGRAM yy_pop_state(); unput_text(0); +} + + /* decl_state -> INITIAL */ +{ +END_FUNCTION BEGIN(INITIAL); return END_FUNCTION; +END_FUNCTION_BLOCK BEGIN(INITIAL); return END_FUNCTION_BLOCK; +END_PROGRAM BEGIN(INITIAL); return END_PROGRAM; +} + /* config -> INITIAL */ +END_CONFIGURATION BEGIN(INITIAL); return END_CONFIGURATION; + + + + /***************************************/ + /* Next is to to remove all whitespace */ + /***************************************/ + /* NOTE: pragmas are handled right at the beginning... */ + +{st_whitespace_no_pragma} /* Eat any whitespace */ +{il_whitespace_no_pragma} /* Eat any whitespace */ + + + + /*****************************************/ + /* B.1.1 Letters, digits and identifiers */ + /*****************************************/ + /* NOTE: 'R1', 'IN', etc... are IL operators, and therefore tokens + * On the other hand, the spec does not define them as keywords, + * which means they may be re-used for variable names, etc...! + * The syntax parser already caters for the possibility of these + * tokens being used for variable names in their declarations. + * When they are declared, they will be added to the variable symbol table! + * Further appearances of these tokens must no longer be parsed + * as R1_tokens etc..., but rather as variable_name_tokens! + * + * That is why the first thing we do with identifiers, even before + * checking whether they may be a 'keyword', is to check whether + * they have been previously declared as a variable name, + * + * However, we have a dilema! Should we here also check for + * prev_declared_derived_function_name_token? + * If we do, then the 'MOD' default library function (defined in + * the standard) will always be returned as a function name, and + * it will therefore not be possible to use it as an operator as + * in the following ST expression 'X := Y MOD Z;' ! + * If we don't, then even it will not be possible to use 'MOD' + * as a funtion as in 'X := MOD(Y, Z);' + * We solve this by NOT testing for function names here, and + * handling this function and keyword clash in bison! + */ + /* +{identifier} {int token = get_identifier_token(yytext); + // fprintf(stderr, "flex: analysing identifier '%s'...", yytext); + if ((token == prev_declared_variable_name_token) || +// (token == prev_declared_derived_function_name_token) || // DO NOT add this condition! + (token == prev_declared_fb_name_token)) { + // if (token != identifier_token) + // * NOTE: if we replace the above uncommented conditions with + * the simple test of (token != identifier_token), then + * 'MOD' et al must be removed from the + * library_symbol_table as a default function name! + * // + yylval.ID=strdup(yytext); + // fprintf(stderr, "returning token %d\n", token); + return token; + } + // otherwise, leave it for the other lexical parser rules... + // fprintf(stderr, "rejecting\n"); + REJECT; + } + */ + + /******************************************************/ + /******************************************************/ + /******************************************************/ + /***** *****/ + /***** *****/ + /***** N O W D O T H E K E Y W O R D S *****/ + /***** *****/ + /***** *****/ + /******************************************************/ + /******************************************************/ + /******************************************************/ + + +EN return EN; /* Keyword */ +ENO return ENO; /* Keyword */ + + + /******************************/ + /* B 1.2.1 - Numeric Literals */ + /******************************/ +TRUE return TRUE; /* Keyword */ +BOOL#1 return boolean_true_literal_token; +BOOL#TRUE return boolean_true_literal_token; +SAFEBOOL#1 {if (get_opt_safe_extensions()) {return safeboolean_true_literal_token;} else{REJECT;}} /* Keyword (Data Type) */ +SAFEBOOL#TRUE {if (get_opt_safe_extensions()) {return safeboolean_true_literal_token;} else{REJECT;}} /* Keyword (Data Type) */ + +FALSE return FALSE; /* Keyword */ +BOOL#0 return boolean_false_literal_token; +BOOL#FALSE return boolean_false_literal_token; +SAFEBOOL#0 {if (get_opt_safe_extensions()) {return safeboolean_false_literal_token;} else{REJECT;}} /* Keyword (Data Type) */ +SAFEBOOL#FALSE {if (get_opt_safe_extensions()) {return safeboolean_false_literal_token;} else{REJECT;}} /* Keyword (Data Type) */ + + + /************************/ + /* B 1.2.3.1 - Duration */ + /************************/ +t# return T_SHARP; /* Delimiter */ +T# return T_SHARP; /* Delimiter */ +TIME return TIME; /* Keyword (Data Type) */ + + + /************************************/ + /* B 1.2.3.2 - Time of day and Date */ + /************************************/ +TIME_OF_DAY return TIME_OF_DAY; /* Keyword (Data Type) */ +TOD return TIME_OF_DAY; /* Keyword (Data Type) */ +DATE return DATE; /* Keyword (Data Type) */ +d# return D_SHARP; /* Delimiter */ +D# return D_SHARP; /* Delimiter */ +DATE_AND_TIME return DATE_AND_TIME; /* Keyword (Data Type) */ +DT return DATE_AND_TIME; /* Keyword (Data Type) */ + + + /***********************************/ + /* B 1.3.1 - Elementary Data Types */ + /***********************************/ +BOOL return BOOL; /* Keyword (Data Type) */ + +BYTE return BYTE; /* Keyword (Data Type) */ +WORD return WORD; /* Keyword (Data Type) */ +DWORD return DWORD; /* Keyword (Data Type) */ +LWORD return LWORD; /* Keyword (Data Type) */ + +SINT return SINT; /* Keyword (Data Type) */ +INT return INT; /* Keyword (Data Type) */ +DINT return DINT; /* Keyword (Data Type) */ +LINT return LINT; /* Keyword (Data Type) */ + +USINT return USINT; /* Keyword (Data Type) */ +UINT return UINT; /* Keyword (Data Type) */ +UDINT return UDINT; /* Keyword (Data Type) */ +ULINT return ULINT; /* Keyword (Data Type) */ + +REAL return REAL; /* Keyword (Data Type) */ +LREAL return LREAL; /* Keyword (Data Type) */ + +WSTRING return WSTRING; /* Keyword (Data Type) */ +STRING return STRING; /* Keyword (Data Type) */ + +TIME return TIME; /* Keyword (Data Type) */ +DATE return DATE; /* Keyword (Data Type) */ +DT return DT; /* Keyword (Data Type) */ +TOD return TOD; /* Keyword (Data Type) */ +DATE_AND_TIME return DATE_AND_TIME; /* Keyword (Data Type) */ +TIME_OF_DAY return TIME_OF_DAY; /* Keyword (Data Type) */ + + /*****************************************************************/ + /* Keywords defined in "Safety Software Technical Specification" */ + /*****************************************************************/ + /* + * NOTE: The following keywords are define in + * "Safety Software Technical Specification, + * Part 1: Concepts and Function Blocks, + * Version 1.0 – Official Release" + * written by PLCopen - Technical Committee 5 + * + * We only support these extensions and keywords + * if the apropriate command line option is given. + */ +SAFEBOOL {if (get_opt_safe_extensions()) {return SAFEBOOL;} else {REJECT;}} + +SAFEBYTE {if (get_opt_safe_extensions()) {return SAFEBYTE;} else {REJECT;}} +SAFEWORD {if (get_opt_safe_extensions()) {return SAFEWORD;} else {REJECT;}} +SAFEDWORD {if (get_opt_safe_extensions()) {return SAFEDWORD;} else{REJECT;}} +SAFELWORD {if (get_opt_safe_extensions()) {return SAFELWORD;} else{REJECT;}} + +SAFEREAL {if (get_opt_safe_extensions()) {return SAFESINT;} else{REJECT;}} +SAFELREAL {if (get_opt_safe_extensions()) {return SAFELREAL;} else{REJECT;}} + +SAFESINT {if (get_opt_safe_extensions()) {return SAFESINT;} else{REJECT;}} +SAFEINT {if (get_opt_safe_extensions()) {return SAFEINT;} else{REJECT;}} +SAFEDINT {if (get_opt_safe_extensions()) {return SAFEDINT;} else{REJECT;}} +SAFELINT {if (get_opt_safe_extensions()) {return SAFELINT;} else{REJECT;}} + +SAFEUSINT {if (get_opt_safe_extensions()) {return SAFEUSINT;} else{REJECT;}} +SAFEUINT {if (get_opt_safe_extensions()) {return SAFEUINT;} else{REJECT;}} +SAFEUDINT {if (get_opt_safe_extensions()) {return SAFEUDINT;} else{REJECT;}} +SAFEULINT {if (get_opt_safe_extensions()) {return SAFEULINT;} else{REJECT;}} + + /* SAFESTRING and SAFEWSTRING are not yet supported, i.e. checked correctly, in the semantic analyser (stage 3) */ + /* so it is best not to support them at all... */ + /* +SAFEWSTRING {if (get_opt_safe_extensions()) {return SAFEWSTRING;} else{REJECT;}} +SAFESTRING {if (get_opt_safe_extensions()) {return SAFESTRING;} else{REJECT;}} + */ + +SAFETIME {if (get_opt_safe_extensions()) {return SAFETIME;} else{REJECT;}} +SAFEDATE {if (get_opt_safe_extensions()) {return SAFEDATE;} else{REJECT;}} +SAFEDT {if (get_opt_safe_extensions()) {return SAFEDT;} else{REJECT;}} +SAFETOD {if (get_opt_safe_extensions()) {return SAFETOD;} else{REJECT;}} +SAFEDATE_AND_TIME {if (get_opt_safe_extensions()) {return SAFEDATE_AND_TIME;} else{REJECT;}} +SAFETIME_OF_DAY {if (get_opt_safe_extensions()) {return SAFETIME_OF_DAY;} else{REJECT;}} + + /********************************/ + /* B 1.3.2 - Generic data types */ + /********************************/ + /* Strangely, the following symbols do not seem to be required! */ + /* But we include them so they become reserved words, and do not + * get passed up to bison as an identifier... + */ +ANY return ANY; /* Keyword (Data Type) */ +ANY_DERIVED return ANY_DERIVED; /* Keyword (Data Type) */ +ANY_ELEMENTARY return ANY_ELEMENTARY; /* Keyword (Data Type) */ +ANY_MAGNITUDE return ANY_MAGNITUDE; /* Keyword (Data Type) */ +ANY_NUM return ANY_NUM; /* Keyword (Data Type) */ +ANY_REAL return ANY_REAL; /* Keyword (Data Type) */ +ANY_INT return ANY_INT; /* Keyword (Data Type) */ +ANY_BIT return ANY_BIT; /* Keyword (Data Type) */ +ANY_STRING return ANY_STRING; /* Keyword (Data Type) */ +ANY_DATE return ANY_DATE; /* Keyword (Data Type) */ + + + /********************************/ + /* B 1.3.3 - Derived data types */ + /********************************/ +":=" return ASSIGN; /* Delimiter */ +".." return DOTDOT; /* Delimiter */ +TYPE return TYPE; /* Keyword */ +END_TYPE return END_TYPE; /* Keyword */ +ARRAY return ARRAY; /* Keyword */ +OF return OF; /* Keyword */ +STRUCT return STRUCT; /* Keyword */ +END_STRUCT return END_STRUCT; /* Keyword */ + + + /*********************/ + /* B 1.4 - Variables */ + /*********************/ + + /******************************************/ + /* B 1.4.3 - Declaration & Initialisation */ + /******************************************/ +VAR_INPUT return VAR_INPUT; /* Keyword */ +VAR_OUTPUT return VAR_OUTPUT; /* Keyword */ +VAR_IN_OUT return VAR_IN_OUT; /* Keyword */ +VAR_EXTERNAL return VAR_EXTERNAL; /* Keyword */ +VAR_GLOBAL return VAR_GLOBAL; /* Keyword */ +END_VAR return END_VAR; /* Keyword */ +RETAIN return RETAIN; /* Keyword */ +NON_RETAIN return NON_RETAIN; /* Keyword */ +R_EDGE return R_EDGE; /* Keyword */ +F_EDGE return F_EDGE; /* Keyword */ +AT return AT; /* Keyword */ + + + /***********************/ + /* B 1.5.1 - Functions */ + /***********************/ +FUNCTION return FUNCTION; /* Keyword */ +END_FUNCTION return END_FUNCTION; /* Keyword */ +VAR return VAR; /* Keyword */ +CONSTANT return CONSTANT; /* Keyword */ + + + /*****************************/ + /* B 1.5.2 - Function Blocks */ + /*****************************/ +FUNCTION_BLOCK return FUNCTION_BLOCK; /* Keyword */ +END_FUNCTION_BLOCK return END_FUNCTION_BLOCK; /* Keyword */ +VAR_TEMP return VAR_TEMP; /* Keyword */ +VAR return VAR; /* Keyword */ +NON_RETAIN return NON_RETAIN; /* Keyword */ +END_VAR return END_VAR; /* Keyword */ + + + /**********************/ + /* B 1.5.3 - Programs */ + /**********************/ +PROGRAM return PROGRAM; /* Keyword */ +END_PROGRAM return END_PROGRAM; /* Keyword */ + + + /********************************************/ + /* B 1.6 Sequential Function Chart elements */ + /********************************************/ + /* NOTE: the following identifiers/tokens clash with the R and S IL operators, as well + .* as other identifiers that may be used as variable names inside IL and ST programs. + * They will have to be handled when we include parsing of SFC... For now, simply + * ignore them! + */ + +ACTION return ACTION; /* Keyword */ +END_ACTION return END_ACTION; /* Keyword */ + +TRANSITION return TRANSITION; /* Keyword */ +END_TRANSITION return END_TRANSITION; /* Keyword */ +FROM return FROM; /* Keyword */ +TO return TO; /* Keyword */ + +INITIAL_STEP return INITIAL_STEP; /* Keyword */ +STEP return STEP; /* Keyword */ +END_STEP return END_STEP; /* Keyword */ + + /* PRIORITY is not a keyword, so we only return it when + * it is explicitly required and we are not expecting any identifiers + * that could also use the same letter sequence (i.e. an identifier: piority) + */ +PRIORITY return PRIORITY; + +{ +L return L; +D return D; +SD return SD; +DS return DS; +SL return SL; +N return N; +P return P; +R return R; +S return S; +} + + + /********************************/ + /* B 1.7 Configuration elements */ + /********************************/ +CONFIGURATION return CONFIGURATION; /* Keyword */ +END_CONFIGURATION return END_CONFIGURATION; /* Keyword */ +TASK return TASK; /* Keyword */ +RESOURCE return RESOURCE; /* Keyword */ +ON return ON; /* Keyword */ +END_RESOURCE return END_RESOURCE; /* Keyword */ +VAR_CONFIG return VAR_CONFIG; /* Keyword */ +VAR_ACCESS return VAR_ACCESS; /* Keyword */ +END_VAR return END_VAR; /* Keyword */ +WITH return WITH; /* Keyword */ +PROGRAM return PROGRAM; /* Keyword */ +RETAIN return RETAIN; /* Keyword */ +NON_RETAIN return NON_RETAIN; /* Keyword */ +READ_WRITE return READ_WRITE; /* Keyword */ +READ_ONLY return READ_ONLY; /* Keyword */ + + /* PRIORITY, SINGLE and INTERVAL are not a keywords, so we only return them when + * it is explicitly required and we are not expecting any identifiers + * that could also use the same letter sequence (i.e. an identifier: piority, ...) + */ +{ +PRIORITY return PRIORITY; +SINGLE return SINGLE; +INTERVAL return INTERVAL; +} + + /***********************************/ + /* B 2.1 Instructions and Operands */ + /***********************************/ +\n return EOL; + + + /*******************/ + /* B 2.2 Operators */ + /*******************/ + /* NOTE: we can't have flex return the same token for + * ANDN and &N, neither for AND and &, since + * AND and ANDN are considered valid variable + * function or functionblock type names! + * This means that the parser may decide that the + * AND or ANDN strings found in the source code + * are being used as variable names + * and not as operators, and will therefore transform + * these tokens into indentifier tokens! + * We can't have the parser thinking that the source + * code contained the string AND (which may be interpreted + * as a vairable name) when in reality the source code + * merely contained the character &, so we use two + * different tokens for & and AND (and similarly + * ANDN and &N)! + */ + /* The following tokens clash with ST expression operators and Standard Functions */ + /* They are also keywords! */ +AND return AND; /* Keyword */ +MOD return MOD; /* Keyword */ +OR return OR; /* Keyword */ +XOR return XOR; /* Keyword */ +NOT return NOT; /* Keyword */ + + /* The following tokens clash with Standard Functions */ + /* They are keywords because they are a function name */ +{ +ADD return ADD; /* Keyword (Standard Function) */ +DIV return DIV; /* Keyword (Standard Function) */ +EQ return EQ; /* Keyword (Standard Function) */ +GE return GE; /* Keyword (Standard Function) */ +GT return GT; /* Keyword (Standard Function) */ +LE return LE; /* Keyword (Standard Function) */ +LT return LT; /* Keyword (Standard Function) */ +MUL return MUL; /* Keyword (Standard Function) */ +NE return NE; /* Keyword (Standard Function) */ +SUB return SUB; /* Keyword (Standard Function) */ +} + + /* The following tokens clash with SFC action qualifiers */ + /* They are not keywords! */ +{ +S return S; +R return R; +} + + /* The following tokens clash with ST expression operators */ +& return AND2; /* NOT a Delimiter! */ + + /* The following tokens have no clashes */ + /* They are not keywords! */ +{ +LD return LD; +LDN return LDN; +ST return ST; +STN return STN; +S1 return S1; +R1 return R1; +CLK return CLK; +CU return CU; +CD return CD; +PV return PV; +IN return IN; +PT return PT; +ANDN return ANDN; +&N return ANDN2; +ORN return ORN; +XORN return XORN; +CAL return CAL; +CALC return CALC; +CALCN return CALCN; +RET return RET; +RETC return RETC; +RETCN return RETCN; +JMP return JMP; +JMPC return JMPC; +JMPCN return JMPCN; +} + + /***********************/ + /* B 3.1 - Expressions */ + /***********************/ +"**" return OPER_EXP; /* NOT a Delimiter! */ +"<>" return OPER_NE; /* NOT a Delimiter! */ +">=" return OPER_GE; /* NOT a Delimiter! */ +"<=" return OPER_LE; /* NOT a Delimiter! */ +& return AND2; /* NOT a Delimiter! */ +AND return AND; /* Keyword */ +XOR return XOR; /* Keyword */ +OR return OR; /* Keyword */ +NOT return NOT; /* Keyword */ +MOD return MOD; /* Keyword */ + + + /*****************************************/ + /* B 3.2.2 Subprogram Control Statements */ + /*****************************************/ +:= return ASSIGN; /* Delimiter */ +=> return SENDTO; /* Delimiter */ +RETURN return RETURN; /* Keyword */ + + + /********************************/ + /* B 3.2.3 Selection Statements */ + /********************************/ +IF return IF; /* Keyword */ +THEN return THEN; /* Keyword */ +ELSIF return ELSIF; /* Keyword */ +ELSE return ELSE; /* Keyword */ +END_IF return END_IF; /* Keyword */ + +CASE return CASE; /* Keyword */ +OF return OF; /* Keyword */ +ELSE return ELSE; /* Keyword */ +END_CASE return END_CASE; /* Keyword */ + + + /********************************/ + /* B 3.2.4 Iteration Statements */ + /********************************/ +FOR return FOR; /* Keyword */ +TO return TO; /* Keyword */ +BY return BY; /* Keyword */ +DO return DO; /* Keyword */ +END_FOR return END_FOR; /* Keyword */ + +WHILE return WHILE; /* Keyword */ +DO return DO; /* Keyword */ +END_WHILE return END_WHILE; /* Keyword */ + +REPEAT return REPEAT; /* Keyword */ +UNTIL return UNTIL; /* Keyword */ +END_REPEAT return END_REPEAT; /* Keyword */ + +EXIT return EXIT; /* Keyword */ + + + + + + + /********************************************************/ + /********************************************************/ + /********************************************************/ + /***** *****/ + /***** *****/ + /***** N O W W O R K W I T H V A L U E S *****/ + /***** *****/ + /***** *****/ + /********************************************************/ + /********************************************************/ + /********************************************************/ + + + /********************************************/ + /* B.1.4.1 Directly Represented Variables */ + /********************************************/ +{direct_variable} {yylval.ID=strdup(yytext); return get_direct_variable_token(yytext);} + + + /******************************************/ + /* B 1.4.3 - Declaration & Initialisation */ + /******************************************/ +{incompl_location} {yylval.ID=strdup(yytext); return incompl_location_token;} + + + /************************/ + /* B 1.2.3.1 - Duration */ + /************************/ +{fixed_point} {yylval.ID=strdup(yytext); return fixed_point_token;} + +{fixed_point_d} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_d_token;} +{integer_d} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_d_token;} + +{fixed_point_h} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_h_token;} +{integer_h} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_h_token;} + +{fixed_point_m} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_m_token;} +{integer_m} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_m_token;} + +{fixed_point_s} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_s_token;} +{integer_s} {yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_s_token;} + +{fixed_point_ms} {yylval.ID=strdup(yytext); yylval.ID[yyleng-2] = '\0'; return fixed_point_ms_token;} +{integer_ms} {yylval.ID=strdup(yytext); yylval.ID[yyleng-2] = '\0'; return integer_ms_token;} + + + /*******************************/ + /* B.1.2.2 Character Strings */ + /*******************************/ +{double_byte_character_string} {yylval.ID=strdup(yytext); return double_byte_character_string_token;} +{single_byte_character_string} {yylval.ID=strdup(yytext); return single_byte_character_string_token;} + + + /******************************/ + /* B.1.2.1 Numeric literals */ + /******************************/ +{integer} {yylval.ID=strdup(yytext); return integer_token;} +{real} {yylval.ID=strdup(yytext); return real_token;} +{binary_integer} {yylval.ID=strdup(yytext); return binary_integer_token;} +{octal_integer} {yylval.ID=strdup(yytext); return octal_integer_token;} +{hex_integer} {yylval.ID=strdup(yytext); return hex_integer_token;} + + + /*****************************************/ + /* B.1.1 Letters, digits and identifiers */ + /*****************************************/ +{identifier}/({st_whitespace})"=>" {yylval.ID=strdup(yytext); return sendto_identifier_token;} +{identifier}/({il_whitespace})"=>" {yylval.ID=strdup(yytext); return sendto_identifier_token;} +{identifier} {yylval.ID=strdup(yytext); + // printf("returning identifier...: %s, %d\n", yytext, get_identifier_token(yytext)); + return get_identifier_token(yytext);} + + + + + + + /************************************************/ + /************************************************/ + /************************************************/ + /***** *****/ + /***** *****/ + /***** T H E L E F T O V E R S . . . *****/ + /***** *****/ + /***** *****/ + /************************************************/ + /************************************************/ + /************************************************/ + + /* do the single character tokens... + * + * e.g.: ':' '(' ')' '+' '*' ... + */ +. {return yytext[0];} + + +%% + + +/***********************************/ +/* Utility function definitions... */ +/***********************************/ + +/* print the include file stack to stderr... */ +void print_include_stack(void) { + int i; + + if ((include_stack_ptr - 1) >= 0) + fprintf (stderr, "in file "); + for (i = include_stack_ptr - 1; i >= 0; i--) + fprintf (stderr, "included from file %s:%d\n", include_stack[i].filename, include_stack[i].env->lineNumber); +} + + +/* return all the text in the current token back to the input stream, except the first n chars. */ +void unput_text(unsigned int n) { + /* it seems that flex has a bug in that it will not correctly count the line numbers + * if we return newlines back to the input stream. These newlines will be re-counted + * a second time when they are processed again by flex. + * We therefore determine how many newlines are in the text we are returning, + * and decrement the line counter acordingly... + */ + /*unsigned int i; + + for (i = n; i < strlen(yytext); i++) + if (yytext[i] == '\n') + current_tracking->lineNumber--;*/ + + /* now return all the text back to the input stream... */ + yyless(n); +} + + +/* Called by flex when it reaches the end-of-file */ +int yywrap(void) +{ + /* We reached the end of the input file... */ + + /* Should we continue with another file? */ + /* If so: + * open the new file... + * return 0; + */ + + /* to we stop processing... + * + * return 1; + */ + + + return 1; /* Stop scanning at end of input file. */ +} + + + +/*************************************/ +/* Include a main() function to test */ +/* the token parsing by flex.... */ +/*************************************/ +#ifdef TEST_MAIN + +#include "../util/symtable.hh" + +yystype yylval; +YYLTYPE yylloc; + +const char *current_filename; + + + +int get_identifier_token(const char *identifier_str) {return 0;} +int get_direct_variable_token(const char *direct_variable_str) {return 0;} + + +int main(int argc, char **argv) { + + FILE *in_file; + int res; + + if (argc == 1) { + /* Work as an interactive (command line) parser... */ + while((res=yylex())) + fprintf(stderr, "(line %d)token: %d\n", yylineno, res); + } else { + /* Work as non-interactive (file) parser... */ + if((in_file = fopen(argv[1], "r")) == NULL) { + char *errmsg = strdup2("Error opening main file ", argv[1]); + perror(errmsg); + free(errmsg); + return -1; + } + + /* parse the file... */ + yyin = in_file; + current_filename = argv[1]; + while(1) { + res=yylex(); + fprintf(stderr, "(line %d)token: %d (%s)\n", yylineno, res, yylval.ID); + } + } + + return 0; + +} +#endif diff -r 17bffb57a8c5 -r 0f24db96b519 stage1_2/stage1_2.cc --- a/stage1_2/stage1_2.cc Fri Jul 29 16:08:40 2011 +0100 +++ b/stage1_2/stage1_2.cc Fri Aug 19 17:33:57 2011 +0100 @@ -44,7 +44,7 @@ #include "stage1_2.hh" -#include "iec.y.hh" +#include "iec_bison.h" #include "stage1_2_priv.hh" @@ -127,14 +127,14 @@ /* NOTE: only accessed indirectly by the lexical parser (flex) * through the function get_identifier_token() */ -/* NOTE: BOGUS_TOKEN_ID is defined in the bison generated file iec.y.hh. +/* NOTE: BOGUS_TOKEN_ID is defined in the bison generated file iec_bison.h. * We need this constant defined before we can declare the symbol tables. - * However, we cannot #include "iec.y.hh" in this file (stage1_2_priv.hh) directly + * However, we cannot #include "iec_bison.h" in this file (stage1_2_priv.hh) directly * because of the way bison ver. 3.2 is copying all declarations in the prologue - * of iec.y to the iec.y.hh file (including an #include stage1_2_priv.hh). - * So, if we were to include "iec.y.hh" here, we would get a circular include. + * of iec.y to the iec_bison.h file (including an #include stage1_2_priv.hh). + * So, if we were to include "iec_bison.h" here, we would get a circular include. * All this means that whoever includes this file (stage1_2_priv.hh) will need - * to take care to first inlcude iec.y.hh !! + * to take care to first inlcude iec_bison.h !! */ /* A symbol table to store all the library elements */ /* e.g.: diff -r 17bffb57a8c5 -r 0f24db96b519 stage1_2/stage1_2_priv.hh --- a/stage1_2/stage1_2_priv.hh Fri Jul 29 16:08:40 2011 +0100 +++ b/stage1_2/stage1_2_priv.hh Fri Aug 19 17:33:57 2011 +0100 @@ -40,10 +40,10 @@ /* !!! WARNING !!! * * Whoever includes this file (stage1_2_priv.hh) will need - * to first inlcude iec.y.hh !! + * to first inlcude iec_bison.h !! * * Read other comments further down to understand why we don't - * include iec.y.hh in this file. + * include iec_bison.h in this file. */ @@ -186,14 +186,14 @@ * * In essence, they are a data passing mechanism between Bison and Flex. */ -/* NOTE: BOGUS_TOKEN_ID is defined in the bison generated file iec.y.hh. +/* NOTE: BOGUS_TOKEN_ID is defined in the bison generated file iec_bison.h. * We need this constant defined before we can declare the symbol tables. - * However, we cannot #include "iec.y.hh" in this file (stage1_2_priv.hh) directly + * However, we cannot #include "iec_bison.h" in this file (stage1_2_priv.hh) directly * because of the way bison ver. 2.3 is copying all declarations in the prologue - * of iec.y to the iec.y.hh file (including an #include stage1_2_priv.hh). - * So, if we were to include "iec.y.hh" here, we would get a circular include. + * of iec.y to the iec_bison.h file (including an #include stage1_2_priv.hh). + * So, if we were to include "iec_bison.h" here, we would get a circular include. * All this means that whoever includes this file (stage1_2_priv.hh) will need - * to take care to first inlcude iec.y.hh !! + * to take care to first inlcude iec_bison.h !! */ /* A symbol table to store all the library elements */ /* e.g.: