# HG changeset patch
# User etisserant
# Date 1170253958 -3600
# Node ID fb772792efd13d2831f12df6d8aa2a4f2e2927de
Initial commit. Last MatPLC CVS with some makefile inclusion removed in order to compile fine out of MatPLC.
diff -r 000000000000 -r fb772792efd1 .cdtproject
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.cdtproject Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-
+
+
+
+
+
+
diff -r 000000000000 -r fb772792efd1 .project
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.project Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,82 @@
+
+
+ matiec
+
+
+
+
+
+ org.eclipse.cdt.make.core.makeBuilder
+ clean,full,incremental,
+
+
+ org.eclipse.cdt.make.core.build.arguments
+
+
+
+ org.eclipse.cdt.core.errorOutputParser
+ org.eclipse.cdt.core.MakeErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser;org.eclipse.cdt.core.VCErrorParser;
+
+
+ org.eclipse.cdt.make.core.enableAutoBuild
+ false
+
+
+ org.eclipse.cdt.make.core.environment
+
+
+
+ org.eclipse.cdt.make.core.enableFullBuild
+ true
+
+
+ org.eclipse.cdt.make.core.build.target.inc
+ all
+
+
+ org.eclipse.cdt.make.core.enabledIncrementalBuild
+ true
+
+
+ org.eclipse.cdt.make.core.build.target.clean
+ clean
+
+
+ org.eclipse.cdt.make.core.build.command
+ make
+
+
+ org.eclipse.cdt.make.core.enableCleanBuild
+ true
+
+
+ org.eclipse.cdt.make.core.append_environment
+ true
+
+
+ org.eclipse.cdt.make.core.useDefaultBuildCmd
+ true
+
+
+ org.eclipse.cdt.make.core.build.target.auto
+ all
+
+
+ org.eclipse.cdt.make.core.stopOnError
+ false
+
+
+
+
+ org.eclipse.cdt.make.core.ScannerConfigBuilder
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.make.core.makeNature
+ org.eclipse.cdt.make.core.ScannerConfigNature
+ org.eclipse.cdt.core.ccnature
+
+
diff -r 000000000000 -r fb772792efd1 .settings/org.eclipse.cdt.core.prefs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.settings/org.eclipse.cdt.core.prefs Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,3 @@
+#Wed Jan 31 15:26:34 CET 2007
+eclipse.preferences.version=1
+indexerId=org.eclipse.cdt.core.fastIndexer
diff -r 000000000000 -r fb772792efd1 AnnexF/average_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/average_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,18 @@
+ FUNCTION_BLOCK AVERAGE
+ VAR_INPUT
+ RUN : BOOL ; (* 1 = run, 0 = reset *)
+ XIN : REAL ; (* Input variable *)
+ N : INT ; (* 0 <= N < 128 or manufacturer- *)
+ END_VAR (* specified maximum value *)
+ VAR_OUTPUT XOUT : REAL ; END_VAR (* Averaged output *)
+ VAR SUM : REAL := 0.0; (* Running sum *)
+ FIFO : DELAY ; (* N-Element FIFO *)
+ END_VAR
+ SUM := SUM - FIFO.XOUT ;
+ FIFO (RUN := RUN , XIN := XIN, N := N) ;
+ SUM := SUM + FIFO.XOUT ;
+ IF RUN THEN XOUT := SUM/N ;
+ ELSE SUM := N*XIN ; XOUT := XIN ;
+ END_IF ;
+ END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 AnnexF/cmd_monitor_il.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/cmd_monitor_il.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,37 @@
+FUNCTION_BLOCK CMD_MONITOR
+ VAR_INPUT AUTO_CMD : BOOL ; (* Automated command *)
+ AUTO_MODE : BOOL ; (* AUTO_CMD enable *)
+ MAN_CMD : BOOL ; (* Manual Command *)
+ MAN_CMD_CHK : BOOL ; (* Negated MAN_CMD to debounce *)
+ T_CMD_MAX : TIME ; (* Max time from CMD to FDBK *)
+ FDBK : BOOL ; (* Confirmation of CMD completion
+ by operative unit *)
+ ACK : BOOL ; (* Acknowledge/cancel ALRM *)
+ END_VAR
+ VAR_OUTPUT CMD : BOOL ; (* Command to operative unit *)
+ ALRM : BOOL ; (* T_CMD_MAX expired without FDBK *)
+ END_VAR
+ VAR CMD_TMR : TON ; (* CMD-to-FDBK timer *)
+ ALRM_FF : SR ; (* Note over-riding S input: *)
+ END_VAR (* Command must be cancelled before
+ "ACK" can cancel alarm *)
+ (* Function Block Body *)
+LD T_CMD_MAX
+ST CMD_TMR.PT (* Store an input to the TON FB *)
+LD AUTO_CMD
+AND AUTO_MODE
+OR( MAN_CMD
+ANDN AUTO_MODE
+ANDN MAN_CMD_CHK
+)
+ST CMD
+IN CMD_TMR (* Invoke the TON FB *)
+LD CMD_TMR.Q
+ANDN FDBK
+ST ALRM_FF.S1 (* Store an input to the SR FB *)
+LD ACK
+R ALRM_FF (* Invoke the SR FB *)
+LD ALRM_FF.Q1
+ST ALRM
+
+END_FUNCTION_BLOCK
diff -r 000000000000 -r fb772792efd1 AnnexF/cmd_monitor_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/cmd_monitor_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,25 @@
+FUNCTION_BLOCK CMD_MONITOR
+ VAR_INPUT AUTO_CMD : BOOL ; (* Automated command *)
+ AUTO_MODE : BOOL ; (* AUTO_CMD enable *)
+ MAN_CMD : BOOL ; (* Manual Command *)
+ MAN_CMD_CHK : BOOL ; (* Negated MAN_CMD to debounce *)
+ T_CMD_MAX : TIME ; (* Max time from CMD to FDBK *)
+ FDBK : BOOL ; (* Confirmation of CMD completion
+ by operative unit *)
+ ACK : BOOL ; (* Acknowledge/cancel ALRM *)
+ END_VAR
+ VAR_OUTPUT CMD : BOOL ; (* Command to operative unit *)
+ ALRM : BOOL ; (* T_CMD_MAX expired without FDBK *)
+ END_VAR
+ VAR CMD_TMR : TON ; (* CMD-to-FDBK timer *)
+ ALRM_FF : SR ; (* Note over-riding S input: *)
+ END_VAR (* Command must be cancelled before
+ "ACK" can cancel alarm *)
+ (* Function Block Body *)
+ CMD := AUTO_CMD & AUTO_MODE
+ OR MAN_CMD & NOT MAN_CMD_CHK & NOT AUTO_MODE ;
+ CMD_TMR (IN := CMD, PT := T_CMD_MAX);
+ ALRM_FF (S1 := CMD_TMR.Q & NOT FDBK, R := ACK);
+ ALRM := ALRM_FF.Q1;
+
+END_FUNCTION_BLOCK
diff -r 000000000000 -r fb772792efd1 AnnexF/delay_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/delay_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,18 @@
+FUNCTION_BLOCK DELAY (* N-sample delay *)
+ VAR_INPUT
+ RUN : BOOL ; (* 1 = run, 0 = reset *)
+ XIN : REAL ;
+ N : INT (* 0 <= N < 128 or manufacturer- *)
+ END_VAR (* specified maximum value *)
+ VAR_OUTPUT XOUT : REAL; END_VAR (* Delayed output *)
+ VAR X : ARRAY [0..127] (* N-Element queue *)
+ OF REAL; (* with FIFO discipline *)
+ I, IXIN, IXOUT : INT := 0;
+ END_VAR
+ IF RUN THEN IXIN := MOD(IXIN + 1, 128) ; X[IXIN] := XIN ;
+ IXOUT := MOD(IXOUT + 1, 128) ; XOUT := X[IXOUT];
+ ELSE XOUT := XIN ; IXIN := N ; IXOUT := 0;
+ FOR I := 0 TO N DO X[I] := XIN; END_FOR;
+ END_IF ;
+END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 AnnexF/derivative_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/derivative_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,18 @@
+ FUNCTION_BLOCK DERIVATIVE
+ VAR_INPUT
+ RUN : BOOL ; (* 0 = reset *)
+ XIN : REAL ; (* Input to be differentiated *)
+ CYCLE : TIME ; (* Sampling period *)
+ END_VAR
+ VAR_OUTPUT
+ XOUT : REAL ; (* Differentiated output *)
+ END_VAR
+ VAR X1, X2, X3 : REAL ; END_VAR
+ IF RUN THEN
+ XOUT := (3.0 * (XIN - X3) + X1 - X2)
+ / (10.0 * TIME_TO_REAL(CYCLE)) ;
+ X3 := X2 ; X2 := X1 ; X1 := XIN ;
+ ELSE XOUT := 0.0; X1 := XIN ; X2 := XIN ; X3 := XIN ;
+ END_IF ;
+ END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 AnnexF/diffeq_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/diffeq_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,30 @@
+ FUNCTION_BLOCK DIFFEQ
+ VAR_INPUT
+ RUN : BOOL ; (* 1 = run, 0 = reset *)
+ XIN : REAL ;
+ A : ARRAY[1..] OF REAL ; (* Input coefficients *)
+ M : INT ; (* Length of input history *)
+ B : ARRAY[0..] OF REAL ; (* Output coefficients *)
+ N : INT ; (* Length of output history *)
+ END_VAR
+ VAR_OUTPUT XOUT : REAL := 0.0 ; END_VAR
+ VAR (* NOTE : Manufacturer may specify other array sizes *)
+ XI : ARRAY [0..128] OF REAL ; (* Input history *)
+ XO : ARRAY [0..128] OF REAL ; (* Output history *)
+ I : INT ;
+ END_VAR
+ XO[0] := XOUT ; XI[0] := XIN ;
+ XOUT := B[0] * XIN ;
+ IF RUN THEN
+ FOR I := M TO 1 BY -1 DO
+ XOUT := XOUT + A[I] * XO[I] ; XO[I] := XO[I-1];
+ END_FOR;
+ FOR I := N TO 1 BY -1 DO
+ XOUT := XOUT + B[I] * XI[I] ; XI[I] := XI[I-1];
+ END_FOR;
+ ELSE
+ FOR I := 1 TO M DO XO[I] := 0.0; END_FOR;
+ FOR I := 1 TO N DO XI[I] := 0.0; END_FOR;
+ END_IF ;
+ END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 AnnexF/fwd_rev_mon_il.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/fwd_rev_mon_il.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,77 @@
+FUNCTION_BLOCK FWD_REV_MON
+VAR_INPUT AUTO : BOOL ;(* Enable automated commands *)
+ ACK : BOOL ; (* Acknowledge/cancel all alarms *)
+ AUTO_FWD : BOOL ; (* Automated forward command *)
+ MAN_FWD : BOOL ; (* Manual forward command *)
+ MAN_FWD_CHK : BOOL ; (* Negated MAN_FWD for debouncing *)
+ T_FWD_MAX : TIME ; (* Maximum time from FWD_CMD to FWD_FDBK *)
+ FWD_FDBK : BOOL ; (* Confirmation of FWD_CMD completion *)
+ (* by operative unit *)
+ AUTO_REV : BOOL ; (* Automated reverse command *)
+ MAN_REV : BOOL ; (* Manual reverse command *)
+ MAN_REV_CHK : BOOL ; (* Negated MAN_REV for debouncing *)
+ T_REV_MAX : TIME ; (* Maximum time from REV_CMD to REV_FDBK *)
+ REV_FDBK : BOOL ; (* Confirmation of REV_CMD completion *)
+END_VAR (* by operative unit *)
+VAR_OUTPUT KLAXON : BOOL ; (* Any alarm active *)
+ FWD_REV_ALRM : BOOL; (* Forward/reverse command conflict *)
+ FWD_CMD : BOOL ; (* "Forward" command to operative unit *)
+ FWD_ALRM : BOOL ; (* T_FWD_MAX expired without FWD_FDBK *)
+ REV_CMD : BOOL ; (* "Reverse" command to operative unit *)
+ REV_ALRM : BOOL ; (* T_REV_MAX expired without REV_FDBK *)
+END_VAR
+VAR FWD_MON : CMD_MONITOR; (* "Forward" command monitor *)
+ REV_MON : CMD_MONITOR; (* "Reverse" command monitor *)
+ FWD_REV_FF : SR ; (* Forward/Reverse contention latch *)
+END_VAR
+(* Function Block body *)
+LD AUTO (* Load common inputs *)
+ST FWD_MON.AUTO_MODE
+ST REV_MON.AUTO_MODE
+LD ACK
+ST FWD_MON.ACK
+ST REV_MON.ACK
+ST FWD_REV_FF.R
+LD AUTO_FWD (* Load inputs to FWD_MON *)
+ST FWD_MON.AUTO_CMD
+LD MAN_FWD
+ST FWD_MON.MAN_CMD
+LD MAN_FWD_CHK
+ST FWD_MON.MAN_CMD_CHK
+LD T_FWD_MAX
+ST FWD_MON.T_CMD_MAX
+LD FWD_FDBK
+ST FWD_MON.FDBK
+CAL FWD_MON (* Activate FWD_MON *)
+LD AUTO_REV (* Load inputs to REV_MON *)
+ST REV_MON.AUTO_CMD
+LD MAN_REV
+ST REV_MON.MAN_CMD
+LD MAN_REV_CHK
+ST REV_MON.MAN_CMD_CHK
+LD T_REV_MAX
+ST REV_MON.T_CMD_MAX
+LD REV_FDBK
+ST REV_MON.FDBK
+CAL REV_MON (* Activate REV_MON *)
+LD FWD_MON.CMD (* Check for contention *)
+AND REV_MON.CMD
+S1 FWD_REV_FF (* Latch contention condition *)
+LD FWD_REV_FF.Q
+ST FWD_REV_ALRM (* Contention alarm *)
+LD FWD_MON.CMD (* "Forward" command and alarm *)
+ANDN FWD_REV_ALRM
+ST FWD_CMD
+LD FWD_MON.ALRM
+ST FWD_ALRM
+LD REV_MON.CMD (* "Reverse" command and alarm *)
+ANDN FWD_REV_ALRM
+ST REV_CMD
+LD REV_MON.ALRM
+ST REV_ALRM
+OR FWD_ALRM (* OR all alarms *)
+OR FWD_REV_ALRM
+ST KLAXON
+
+END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 AnnexF/fwd_rev_mon_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/fwd_rev_mon_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,53 @@
+FUNCTION_BLOCK FWD_REV_MON
+VAR_INPUT AUTO : BOOL ;(* Enable automated commands *)
+ ACK : BOOL ; (* Acknowledge/cancel all alarms *)
+ AUTO_FWD : BOOL ; (* Automated forward command *)
+ MAN_FWD : BOOL ; (* Manual forward command *)
+ MAN_FWD_CHK : BOOL ; (* Negated MAN_FWD for debouncing *)
+ T_FWD_MAX : TIME ; (* Maximum time from FWD_CMD to FWD_FDBK *)
+ FWD_FDBK : BOOL ; (* Confirmation of FWD_CMD completion *)
+ (* by operative unit *)
+ AUTO_REV : BOOL ; (* Automated reverse command *)
+ MAN_REV : BOOL ; (* Manual reverse command *)
+ MAN_REV_CHK : BOOL ; (* Negated MAN_REV for debouncing *)
+ T_REV_MAX : TIME ; (* Maximum time from REV_CMD to REV_FDBK *)
+ REV_FDBK : BOOL ; (* Confirmation of REV_CMD completion *)
+END_VAR (* by operative unit *)
+VAR_OUTPUT KLAXON : BOOL ; (* Any alarm active *)
+ FWD_REV_ALRM : BOOL; (* Forward/reverse command conflict *)
+ FWD_CMD : BOOL ; (* "Forward" command to operative unit *)
+ FWD_ALRM : BOOL ; (* T_FWD_MAX expired without FWD_FDBK *)
+ REV_CMD : BOOL ; (* "Reverse" command to operative unit *)
+ REV_ALRM : BOOL ; (* T_REV_MAX expired without REV_FDBK *)
+END_VAR
+VAR FWD_MON : CMD_MONITOR; (* "Forward" command monitor *)
+ REV_MON : CMD_MONITOR; (* "Reverse" command monitor *)
+ FWD_REV_FF : SR ; (* Forward/Reverse contention latch *)
+END_VAR
+(* Function Block body *)
+(* Evaluate internal function blocks *)
+ FWD_MON (AUTO_MODE := AUTO,
+ ACK := ACK,
+ AUTO_CMD := AUTO_FWD,
+ MAN_CMD := MAN_FWD,
+ MAN_CMD_CHK := MAN_FWD_CHK,
+ T_CMD_MAX := T_FWD_MAX,
+ FDBK := FWD_FDBK);
+ REV_MON (AUTO_MODE := AUTO,
+ ACK := ACK,
+ AUTO_CMD := AUTO_REV,
+ MAN_CMD := MAN_REV,
+ MAN_CMD_CHK := MAN_REV_CHK,
+ T_CMD_MAX := T_REV_MAX,
+ FDBK := REV_FDBK);
+ FWD_REV_FF (S1 := FWD_MON.CMD & REV_MON.CMD, R := ACK);
+(* Transfer data to outputs *)
+ FWD_REV_ALRM := FWD_REV_FF.Q1;
+ FWD_CMD := FWD_MON.CMD & NOT FWD_REV_ALRM;
+ FWD_ALRM := FWD_MON.ALRM;
+ REV_CMD := REV_MON.CMD & NOT FWD_REV_ALRM;
+ REV_ALRM := REV_MON.ALRM;
+ KLAXON := FWD_ALRM OR REV_ALRM OR FWD_REV_ALRM;
+
+END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 AnnexF/gravel_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/gravel_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,129 @@
+PROGRAM GRAVEL (* Gravel measurement and loading system *)
+ VAR_INPUT
+ OFF_PB : BOOL ;
+ ON_PB : BOOL ;
+ FILL_PB : BOOL ;
+ SIREN_ACK : BOOL ;
+ LOAD_PB : BOOL ; (* Load truck from bin *)
+ JOG_PB : BOOL ;
+ LAMP_TEST : BOOL ;
+ TRUCK_ON_RAMP : BOOL ; (* Optical sensor *)
+ SILO_EMPTY_LS : BOOL ;
+ BIN_EMPTY_LS : BOOL ;
+ SETPOINT : BYTE ; (* 2-digit BCD *)
+ END_VAR
+ VAR_OUTPUT
+ CONTROL_LAMP : BOOL ;
+ TRUCK_LAMP : BOOL ;
+ SILO_EMPTY_LAMP : BOOL ;
+ CONVEYOR_LAMP : BOOL ;
+ CONVEYOR_MOTOR : BOOL ;
+ SILO_VALVE : BOOL ;
+ BIN_VALVE : BOOL ;
+ SIREN : BOOL ;
+ BIN_LEVEL : BYTE ;
+ END_VAR
+ VAR
+ BLINK_TIME : TIME; (* BLINK ON/OFF time *)
+ PULSE_TIME : TIME; (* LEVEL_CTR increment interval *)
+ RUNOUT_TIME: TIME; (* Conveyor running time after loading *)
+ RUN_IN_TIME: TIME; (* Conveyor running time before loading *)
+ SILENT_TIME: TIME; (* Siren silent time after SIREN_ACK *)
+ OK_TO_RUN : BOOL; (* 1 = Conveyor is allowed to run *)
+ (* Function Blocks *)
+ BLINK: TON; (* Blinker OFF period timer / ON output *)
+ BLANK: TON; (* Blinker ON period timer / blanking pulse *)
+ PULSE: TON; (* LEVEL_CTR pulse interval timer *)
+ SIREN_FF: RS;
+ SILENCE_TMR: TP; (* Siren silent period timer *)
+ END_VAR
+ VAR RETAIN LEVEL_CTR : CTU ; END_VAR
+ (* Program body *)
+ (* Major operating states *)
+ INITIAL_STEP START : END_STEP
+ TRANSITION FROM START TO FILL_BIN
+ := FILL_PB & CONTROL.X ; END_TRANSITION
+ STEP FILL_BIN: SILO_VALVE(N); END_STEP
+ TRANSITION FROM FILL_BIN TO START
+ := NOT FILL_PB OR NOT CONTROL.X ; END_TRANSITION
+ TRANSITION FROM FILL_BIN TO LOAD_WAIT := LEVEL_CTR.Q ;
+ END_TRANSITION
+ STEP LOAD_WAIT : END_STEP
+ TRANSITION FROM LOAD_WAIT TO RUN_IN
+ := LOAD_PB & OK_TO_RUN ; END_TRANSITION
+ STEP RUN_IN : END_STEP
+ TRANSITION FROM RUN_IN TO LOAD_WAIT := NOT OK_TO_RUN ;
+ END_TRANSITION
+ TRANSITION FROM RUN_IN TO DUMP_BIN
+ := RUN_IN.T > RUN_IN_TIME;
+ END_TRANSITION
+ STEP DUMP_BIN: BIN_VALVE(N); END_STEP
+ TRANSITION FROM DUMP_BIN TO LOAD_WAIT := NOT OK_TO_RUN ;
+ END_TRANSITION
+ TRANSITION FROM DUMP_BIN TO RUNOUT := BIN_EMPTY_LS ;
+ END_TRANSITION
+ STEP RUNOUT : END_STEP
+ TRANSITION FROM RUNOUT TO LOAD_WAIT := NOT OK_TO_RUN ;
+ END_TRANSITION
+ TRANSITION FROM RUNOUT TO START
+ := RUNOUT.T >= RUNOUT_TIME ; END_TRANSITION
+(* Control state sequencing *)
+INITIAL_STEP CONTROL_OFF: END_STEP
+TRANSITION FROM CONTROL_OFF TO CONTROL
+ := ON_PB & NOT OFF_PB ; END_TRANSITION
+STEP CONTROL: CONTROL_ACTION(N); END_STEP
+ACTION CONTROL_ACTION:
+ BLINK(EN:=CONTROL.X & NOT BLANK.Q, PT := BLINK_TIME) ;
+ BLANK(EN:=BLINK.Q, PT := BLINK_TIME) ;
+ OK_TO_RUN := CONTROL.X & TRUCK_ON_RAMP ;
+ CONVEYOR_MOTOR :=
+ OK_TO_RUN & OR(JOG_PB, RUN_IN.X, DUMP_BIN.X, RUNOUT.X);
+END_ACTION
+TRANSITION FROM CONTROL TO CONTROL_OFF := OFF_PB ;
+END_TRANSITION
+(* Monitor Logic *)
+INITIAL_STEP MONITOR: MONITOR_ACTION(N); END_STEP
+ACTION MONITOR_ACTION:
+ CONVEYOR_LAMP := CONVEYOR_MOTOR & BLINK.Q ;
+ CONTROL_LAMP := CONTROL.X OR LAMP_TEST ;
+ TRUCK_LAMP := TRUCK_ON_RAMP OR LAMP_TEST ;
+ SILO_EMPTY_LAMP := BLINK.Q & SILO_EMPTY_LS OR LAMP_TEST ;
+ SILENCE_TMR(IN:=SIREN_ACK, PT:=SILENT_TIME) ;
+ SIREN_FF(S:=SILO_EMPTY_LS, R1:=SILENCE_TMR.Q) ;
+ SIREN := SIREN_FF.Q1 ;
+ PULSE(IN:=FILL_BIN.X & NOT PULSE.Q, PT:=PULSE_TIME) ;
+ LEVEL_CTR(R := BIN_EMPTY_LS, CU := PULSE.Q,
+ PV := BCD_TO_INT(SETPOINT)) ;
+ BIN_LEVEL := INT_TO_BCD(LEVEL_CTR.CV) ;
+END_ACTION
+
+END_PROGRAM
+
+ CONFIGURATION GRAVEL_CONTROL
+ RESOURCE PROC1 ON PROC_TYPE_Y
+ PROGRAM G : GRAVEL
+ (* Inputs *)
+ (OFF_PB := %I0.0 ,
+ ON_PB := %I0.1 ,
+ FILL_PB := %I0.2 ,
+ SIREN_ACK := %I0.3 ,
+ LOAD_PB := %I0.4 ,
+ JOG_PB := %I0.5 ,
+ LAMP_TEST := %I0.7 ,
+ TRUCK_ON_RAMP := %I1.4 ,
+ SILO_EMPTY_LS := %I1.5 ,
+ BIN_EMPTY_LS := %I1.6 ,
+ SETPOINT := %IB2 ,
+ (* Outputs *)
+ CONTROL_LAMP => %Q4.0,
+ TRUCK_LAMP => %Q4.2,
+ SILO_EMPTY_LAMP => %Q4.3,
+ CONVEYOR_LAMP => %Q5.3,
+ CONVEYOR_MOTOR => %Q5.4,
+ SILO_VALVE => %Q5.5,
+ BIN_VALVE => %Q5.6,
+ SIREN => %Q5.7,
+ BIN_LEVEL => %B6) ;
+ END_RESOURCE
+ END_CONFIGURATION
+
diff -r 000000000000 -r fb772792efd1 AnnexF/hysteresis_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/hysteresis_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,10 @@
+FUNCTION_BLOCK HYSTERESIS
+ (* Boolean hysteresis on difference *)
+ (* of REAL inputs, XIN1 - XIN2 *)
+ VAR_INPUT XIN1, XIN2, EPS : REAL; END_VAR
+ VAR_OUTPUT Q : BOOL := 0; END_VAR
+ IF Q THEN IF XIN1 < (XIN2 - EPS) THEN Q := 0; END_IF ;
+ ELSIF XIN1 > (XIN2 + EPS) THEN Q := 1 ;
+ END_IF ;
+END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 AnnexF/integral_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/integral_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,18 @@
+ FUNCTION_BLOCK INTEGRAL
+ VAR_INPUT
+ RUN : BOOL ; (* 1 = integrate, 0 = hold *)
+ R1 : BOOL ; (* Overriding reset *)
+ XIN : REAL ; (* Input variable *)
+ X0 : REAL ; (* Initial value *)
+ CYCLE : TIME ; (* Sampling period *)
+ END_VAR
+ VAR_OUTPUT
+ Q : BOOL ; (* NOT R1 *)
+ XOUT : REAL ; (* Integrated output *)
+ END_VAR
+ Q := NOT R1 ;
+ IF R1 THEN XOUT := X0 ;
+ ELSIF RUN THEN XOUT := XOUT + XIN * TIME_TO_REAL(CYCLE);
+ END_IF ;
+ END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 AnnexF/lag1_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/lag1_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,16 @@
+ FUNCTION_BLOCK LAG1
+ VAR_INPUT
+ RUN : BOOL ; (* 1 = run, 0 = reset *)
+ XIN : REAL ; (* Input variable *)
+ TAU : TIME ; (* Filter time constant *)
+ CYCLE : TIME ; (* Sampling time interval *)
+ END_VAR
+ VAR_OUTPUT XOUT : REAL ; END_VAR (* Filtered output *)
+ VAR K : REAL ; (* Smoothing constant, 0.0<=K<1.0 *)
+ END_VAR
+ IF RUN THEN XOUT := XOUT + K * (XIN - XOUT) ;
+ ELSE XOUT := XIN ;
+ K := TIME_TO_REAL(CYCLE) / TIME_TO_REAL(CYCLE + TAU) ;
+ END_IF ;
+ END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 AnnexF/pid_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/pid_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,25 @@
+ FUNCTION_BLOCK PID
+ VAR_INPUT
+ AUTO : BOOL ; (* 0 - manual , 1 - automatic *)
+ PV : REAL ; (* Process variable *)
+ SP : REAL ; (* Set point *)
+ X0 : REAL ; (* Manual output adjustment - *)
+ (* Typically from transfer station *)
+ KP : REAL ; (* Proportionality constant *)
+ TR : REAL ; (* Reset time *)
+ TD : REAL ; (* Derivative time constant *)
+ CYCLE : TIME ; (* Sampling period *)
+ END_VAR
+ VAR_OUTPUT XOUT : REAL; END_VAR
+ VAR ERROR : REAL ; (* PV - SP *)
+ ITERM : INTEGRAL ; (* FB for integral term *)
+ DTERM : DERIVATIVE ; (* FB for derivative term *)
+ END_VAR
+ ERROR := PV - SP ;
+ (*** Adjust ITERM so that XOUT := X0 when AUTO = 0 ***)
+ ITERM (RUN := AUTO, R1 := NOT AUTO, XIN := ERROR,
+ X0 := TR * (X0 - ERROR), CYCLE := CYCLE) ;
+ DTERM (RUN := AUTO, XIN := ERROR, CYCLE := CYCLE) ;
+ XOUT := KP * (ERROR + ITERM.XOUT/TR + DTERM.XOUT*TD) ;
+ END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 AnnexF/ramp_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/ramp_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,25 @@
+ FUNCTION_BLOCK RAMP
+ VAR_INPUT
+ RUN : BOOL ; (* 0 - track X0, 1 - ramp to/track X1 *)
+ X0,X1 : REAL ;
+ TR : TIME ; (* Ramp duration *)
+ CYCLE : TIME ; (* Sampling period *)
+ END_VAR
+ VAR_OUTPUT
+ BUSY : BOOL ; (* BUSY = 1 during ramping period *)
+ XOUT : REAL := 0.0 ;
+ END_VAR
+ VAR XI : REAL ; (* Initial value *)
+ T : TIME := T#0s; (* Elapsed time of ramp *)
+ END_VAR
+ BUSY := RUN ;
+ IF RUN THEN
+ IF T >= TR THEN BUSY := 0 ; XOUT := X1 ;
+ ELSE XOUT := XI + (X1-XI) * TIME_TO_REAL(T)
+ / TIME_TO_REAL(TR) ;
+ T := T + CYCLE ;
+ END_IF ;
+ ELSE XOUT := X0 ; XI := X0 ; T := t#0s ;
+ END_IF ;
+ END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 AnnexF/readme
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/readme Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,6 @@
+ IEC 61131-3 Annex F Examples (informative)
+
+This directory contains example code take from:
+
+Annex F of Draft 2nd edition of the IEC 61131-3 standard (1998)
+"PROGRAMMABLE CONTROLLERS - PROGRAMMING LANGUAGES"
diff -r 000000000000 -r fb772792efd1 AnnexF/stack_int_il.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/stack_int_il.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,58 @@
+FUNCTION_BLOCK STACK_INT
+ VAR_INPUT PUSH, POP: BOOL R_EDGE; (* Basic stack operations *)
+ R1 : BOOL ; (* Over-riding reset *)
+ IN : INT ; (* Input to be pushed *)
+ N : INT ; (* Maximum depth after reset *)
+ END_VAR
+ VAR_OUTPUT EMPTY : BOOL := 1 ; (* Stack empty *)
+ OFLO : BOOL := 0 ; (* Stack overflow *)
+ OUT : INT := 0 ; (* Top of stack data *)
+ END_VAR
+ VAR STK : ARRAY[0..127] OF INT; (* Internal stack *)
+ NI : INT :=128 ; (* Storage for N upon reset *)
+ PTR : INT := -1 ; (* Stack pointer *)
+ END_VAR
+ (* Function Block body *)
+ LD R1 (* Dispatch on operations *)
+ JMPC RESET
+ LD POP
+ ANDN EMPTY (* Don't pop empty stack *)
+ JMPC POP_STK
+ LD PUSH
+ ANDN OFLO (* Don't push overflowed stack *)
+ JMPC PUSH_STK
+ RET (* Return if no operations active *)
+RESET: LD 0 (* Stack reset operations *)
+ ST OFLO
+ LD 1
+ ST EMPTY
+ LD -1
+ ST PTR
+ CAL LIMIT(MN:=1,IN:=N,MX:=128)
+ ST NI
+ JMP ZRO_OUT
+POP_STK: LD 0
+ ST OFLO (* Popped stack is not overflowing *)
+ LD PTR
+ SUB 1
+ ST PTR
+ LT 0 (* Empty when PTR < 0 *)
+ ST EMPTY
+ JMPC ZRO_OUT
+ LD STK[PTR]
+ JMP SET_OUT
+PUSH_STK: LD 0
+ ST EMPTY (* Pushed stack is not empty *)
+ LD PTR
+ ADD 1
+ ST PTR
+ EQ NI (* Overflow when PTR = NI *)
+ ST OFLO
+ JMPC ZRO_OUT
+ LD IN
+ ST STK[PTR] (* Push IN onto STK *)
+ JMP SET_OUT
+ZRO_OUT: LD 0 (* OUT=0 for EMPTY or OFLO *)
+SET_OUT: ST OUT
+
+ END_FUNCTION_BLOCK
diff -r 000000000000 -r fb772792efd1 AnnexF/stack_int_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/stack_int_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,31 @@
+FUNCTION_BLOCK STACK_INT
+ VAR_INPUT PUSH, POP: BOOL R_EDGE; (* Basic stack operations *)
+ R1 : BOOL ; (* Over-riding reset *)
+ IN : INT ; (* Input to be pushed *)
+ N : INT ; (* Maximum depth after reset *)
+ END_VAR
+ VAR_OUTPUT EMPTY : BOOL := 1 ; (* Stack empty *)
+ OFLO : BOOL := 0 ; (* Stack overflow *)
+ OUT : INT := 0 ; (* Top of stack data *)
+ END_VAR
+ VAR STK : ARRAY[0..127] OF INT; (* Internal stack *)
+ NI : INT :=128 ; (* Storage for N upon reset *)
+ PTR : INT := -1 ; (* Stack pointer *)
+ END_VAR
+ (* Function Block body *)
+ IF R1 THEN
+ OFLO := 0; EMPTY := 1; PTR := -1;
+ NI := LIMIT (MN:=1,IN:=N,MX:=128); OUT := 0;
+ ELSIF POP & NOT EMPTY THEN
+ OFLO := 0; PTR := PTR-1; EMPTY := PTR < 0;
+ IF EMPTY THEN OUT := 0;
+ ELSE OUT := STK[PTR];
+ END_IF ;
+ ELSIF PUSH & NOT OFLO THEN
+ EMPTY := 0; PTR := PTR+1; OFLO := (PTR = NI);
+ IF NOT OFLO THEN OUT := IN ; STK[PTR] := IN;
+ ELSE OUT := 0;
+ END_IF ;
+ END_IF ;
+
+ END_FUNCTION_BLOCK
diff -r 000000000000 -r fb772792efd1 AnnexF/transfer_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/transfer_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,25 @@
+FUNCTION_BLOCK TRANSFER
+ VAR_INPUT
+ AUTO : BOOL ; (* 1 - track X0, 0 - ramp or hold *)
+ XIN : REAL ; (* Typically from PID Function Block *)
+ FAST_RATE, SLOW_RATE : REAL ; (* Up/down ramp slopes *)
+ FAST_UP, SLOW_UP, (* Typically pushbuttons *)
+ FAST_DOWN, SLOW_DOWN : BOOL;
+ CYCLE : TIME ; (* Sampling period *)
+ END_VAR
+ VAR_OUTPUT XOUT : REAL ; END_VAR
+ VAR XFER_RAMP : INTEGRAL ;
+ RAMP_RATE : REAL ;
+ END_VAR
+ RAMP_RATE := 0.0 ;
+ IF NOT AUTO THEN
+ IF FAST_UP THEN RAMP_RATE := FAST_RATE; END_IF;
+ IF SLOW_UP THEN RAMP_RATE := RAMP_RATE + SLOW_RATE; END_IF;
+ IF FAST_DOWN THEN RAMP_RATE := RAMP_RATE - FAST_RATE; END_IF;
+ IF SLOW_DOWN THEN RAMP_RATE := RAMP_RATE - SLOW_RATE; END_IF;
+ END_IF ;
+ XFER_RAMP (RUN := 1, CYCLE := CYCLE, R1 := AUTO,
+ XIN := RAMP_RATE, X0 := XIN) ;
+ XOUT := XFER_RAMP.XOUT;
+END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 AnnexF/weigh_il.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/weigh_il.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,18 @@
+FUNCTION WEIGH : WORD (* BCD encoded *)
+ VAR_INPUT (* "EN" input is used to indicate "scale ready" *)
+ weigh_command : BOOL;
+ gross_weight : WORD ; (* BCD encoded *)
+ tare_weight : INT ;
+ END_VAR
+(* Function Body *)
+ LD weigh_command
+ JMPC WEIGH_NOW
+ ST ENO (* No weighing, 0 to "ENO" *)
+ RET
+WEIGH_NOW: LD gross_weight
+ BCD_TO_INT
+ SUB tare_weight
+ INT_TO_BCD (* Return evaluated weight *)
+ ST WEIGH
+
+END_FUNCTION (* Implicit "ENO" *)
diff -r 000000000000 -r fb772792efd1 AnnexF/weigh_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AnnexF/weigh_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,12 @@
+FUNCTION WEIGH : WORD (* BCD encoded *)
+ VAR_INPUT (* "EN" input is used to indicate "scale ready" *)
+ weigh_command : BOOL;
+ gross_weight : WORD ; (* BCD encoded *)
+ tare_weight : INT ;
+ END_VAR
+(* Function Body *)
+IF weigh_command THEN
+ WEIGH := INT_TO_BCD (BCD_TO_INT(gross_weight) - tare_weight);
+END_IF ;
+
+END_FUNCTION (* Implicit "ENO" *)
diff -r 000000000000 -r fb772792efd1 Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,63 @@
+# include the system specific Makefile
+#include ../../Makefile.$(shell uname)
+
+default: all
+
+all: iec2cc iec2iec
+
+install: all
+ install -d $(INSTALL_PREDIR)/$(INSTALL_BINDIR)/
+ install -d $(INSTALL_PREDIR)/$(IECLIBDIR)/
+ install iec2cc $(INSTALL_PREDIR)/$(INSTALL_BINDIR)/
+ install lib/*.txt $(INSTALL_PREDIR)/$(IECLIBDIR)/
+# install iec2iec $(INSTALL_PREDIR)/$(INSTALL_BINDIR)/
+
+
+uninstall:
+ rm -f $(INSTALL_PREDIR)/$(INSTALL_BINDIR)/iec2cc
+ rm -f $(INSTALL_PREDIR)/$(INSTALL_BINDIR)/iec2iec
+ for ff in `cd lib; ls *.txt; cd ..` do echo $$ff done
+# for ff in `cd lib; ls *.txt; cd ..` do rm -f $(INSTALL_PREDIR)/$(IECLIBDIR)/$$ff done
+
+
+clean:
+ -rm -f iec2iec iec2cc *.o absyntax/*.o Makefile.depend
+# make something everywhere (ie, in all Makefiles that have that target)
+ find . -depth -mindepth 2 -maxdepth 2 -name Makefile -printf %h\\n | xargs -i make -C{} $@
+
+
+
+#get warnings, debugging information and optimization
+CXXFLAGS = -Wall -pedantic -Wpointer-arith -Wwrite-strings
+# CXXFLAGS += -Werror
+CXXFLAGS += -ggdb -O3 -funroll-loops
+# Note: if the optimizer crashes, we'll leave out the -O3 for those files
+
+CXXFLAGS += -I.
+
+
+
+LIBS = absyntax/absyntax.o absyntax/visitor.o
+LIBS += stage1_2/iec.y.o stage1_2/iec.flex.o
+
+iec2cc: main.o stage4/generate_cc/generate_cc.o stage4/stage4.o $(LIBS)
+ $(CXX) -o iec2cc main.o stage4/stage4.o stage4/generate_cc/generate_cc.o $(LIBS)
+
+
+iec2iec: main.o stage4/generate_iec/generate_iec.o stage4/stage4.o $(LIBS)
+ $(CXX) -o iec2iec main.o stage4/stage4.o stage4/generate_iec/generate_iec.o $(LIBS)
+
+
+#how to make things in subdirectories etc
+../% /% absyntax/% stage1_2/% stage3/% stage4/% util/%:
+ $(MAKE) -C $(@D) $(@F)
+
+Makefile.depend depend:
+ $(CXX) -MM -MG -I. *.cc \
+ | perl -pe 's/:/ Makefile.depend:/' > Makefile.depend
+
+include Makefile.depend
+
+
+
+
diff -r 000000000000 -r fb772792efd1 absyntax/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax/Makefile Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,30 @@
+# include the system specific Makefile
+#include ../../../Makefile.$(shell uname)
+
+
+
+
+default: all
+
+all: absyntax.o visitor.o
+
+clean:
+ rm -f *.o
+ find . -depth -mindepth 2 -maxdepth 2 -name Makefile -printf %h\\n | xargs -i make -C{} $@
+
+
+#get warnings, debugging information and optimization
+CXXFLAGS = -Wall -pedantic -Wpointer-arith -Wwrite-strings
+# CXXFLAGS += -Werror
+
+CXXFLAGS += -ggdb -O3 -funroll-loops
+# Note: if the optimizer crashes, we'll leave out the -O3 for those files
+
+CXXFLAGS += -I. -I../* -I../../absyntax
+
+
+
+#how to make things in subdirectories etc
+../% /% absyntax/% stage1_2/% stage3/% stage4/% util/%:
+ $(MAKE) -C $(@D) $(@F)
+
diff -r 000000000000 -r fb772792efd1 absyntax/absyntax.cc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax/absyntax.cc Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,159 @@
+/*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+/*
+ * Definition of the Abstract Syntax data structure components
+ */
+
+#include
+#include /* required for exit() */
+#include
+
+#include "absyntax.hh"
+//#include "../stage1_2/iec.hh" /* required for BOGUS_TOKEN_ID, etc... */
+#include "visitor.hh"
+
+#define ABORT(str) {printf("ERROR: %s\n", str); exit(0);}
+
+
+
+symbol_c *tree_root = NULL;
+
+
+
+
+/* The base class of all symbols */
+symbol_c::symbol_c(void) {
+ lineno = 0;
+}
+
+symbol_c::symbol_c(long lineno) {
+ this->lineno = lineno;
+}
+
+
+
+token_c::token_c(const char *value) {
+ this->value = value;
+// printf("New token: %s\n", value);
+}
+
+
+
+
+
+
+list_c::list_c(void) {
+ n = 0;
+ elements = NULL;
+}
+
+list_c::list_c(symbol_c *elem) {
+ n = 0;
+ elements = NULL;
+ add_element(elem);
+}
+
+/* insert a new element */
+void list_c::add_element(symbol_c *elem) {
+//printf("list_c::add_element()\n");
+ n++;
+ elements = (symbol_c **)realloc(elements, n * sizeof(symbol_c *));
+ if (elements == NULL)
+ ABORT("Out of memory");
+ elements[n - 1] = elem;
+}
+
+
+
+
+
+#define SYM_LIST(class_name_c) \
+void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);}
+
+#define SYM_TOKEN(class_name_c) \
+class_name_c::class_name_c(const char *value): token_c(value) {} \
+void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);}
+
+#define SYM_REF0(class_name_c) \
+void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);}
+
+
+#define SYM_REF2(class_name_c, ref1, ref2) \
+class_name_c::class_name_c(symbol_c *ref1, \
+ symbol_c *ref2) { \
+ this->ref1 = ref1; \
+ this->ref2 = ref2; \
+} \
+void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);}
+
+
+#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4) \
+class_name_c::class_name_c(symbol_c *ref1, \
+ symbol_c *ref2, \
+ symbol_c *ref3, \
+ symbol_c *ref4) { \
+ this->ref1 = ref1; \
+ this->ref2 = ref2; \
+ this->ref3 = ref3; \
+ this->ref4 = ref4; \
+} \
+void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);}
+
+
+#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6) \
+class_name_c::class_name_c(symbol_c *ref1, \
+ symbol_c *ref2, \
+ symbol_c *ref3, \
+ symbol_c *ref4, \
+ symbol_c *ref5, \
+ symbol_c *ref6) { \
+ this->ref1 = ref1; \
+ this->ref2 = ref2; \
+ this->ref3 = ref3; \
+ this->ref4 = ref4; \
+ this->ref5 = ref5; \
+ this->ref6 = ref6; \
+} \
+void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);}
+
+
+
+#include "absyntax.def"
+
+
+
+
+#undef SYM_LIST
+#undef SYM_TOKEN
+#undef SYM_TOKEN
+#undef SYM_REF0
+#undef SYM_REF2
+#undef SYM_REF4
+#undef SYM_REF6
+
+
+
+
+
diff -r 000000000000 -r fb772792efd1 absyntax/absyntax.def
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax/absyntax.def Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,852 @@
+/*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+/*
+ * Definition of the Abstract Syntax data structure components
+ */
+
+
+/*
+ * ABSYNTAX.DEF
+ *
+ * This generates the parse tree structure used to bind the components
+ * identified by Bison in the correct syntax order. At the end of the
+ * Bison analysis the tree is walked in a sequential fashion generating
+ * the relavent code.
+ */
+
+
+/***************************/
+/* 2.1.6 - Pragmas */
+/***************************/
+SYM_TOKEN(pragma_c)
+
+
+/***************************/
+/* B 0 - Programming Model */
+/***************************/
+SYM_LIST(library_c)
+
+
+/*************************/
+/* B.1 - Common elements */
+/*************************/
+/*******************************************/
+/* B 1.1 - Letters, digits and identifiers */
+/*******************************************/
+SYM_TOKEN(identifier_c)
+
+
+/*********************/
+/* B 1.2 - Constants */
+/*********************/
+
+/******************************/
+/* B 1.2.1 - Numeric Literals */
+/******************************/
+SYM_TOKEN(real_c)
+SYM_TOKEN(integer_c)
+SYM_TOKEN(binary_integer_c)
+SYM_TOKEN(octal_integer_c)
+SYM_TOKEN(hex_integer_c)
+
+/* Note:
+ * We do not have signed_integer_c and signed_real_c classes.
+ * These are stored in the parse tree as a integer_c or real_c
+ * preceded by a unary minus operator.
+ */
+/* Not required:
+SYM_TOKEN(signed_integer_c)
+SYM_TOKEN(signed_real_c)
+*/
+
+SYM_REF2(numeric_literal_c, type, value)
+SYM_REF2(integer_literal_c, type, value)
+SYM_REF2(real_literal_c, type, value)
+SYM_REF2(bit_string_literal_c, type, value)
+SYM_REF2(boolean_literal_c, type, value)
+
+/* helper class for boolean_literal_c */
+SYM_REF0(boolean_true_c)
+
+/* helper class for boolean_literal_c */
+SYM_REF0(boolean_false_c)
+
+
+/*******************************/
+/* B.1.2.2 Character Strings */
+/*******************************/
+SYM_TOKEN(double_byte_character_string_c)
+SYM_TOKEN(single_byte_character_string_c)
+
+
+/***************************/
+/* B 1.2.3 - Time Literals */
+/***************************/
+
+/************************/
+/* B 1.2.3.1 - Duration */
+/************************/
+SYM_REF0(neg_time_c)
+SYM_REF2(duration_c, neg, interval)
+SYM_TOKEN(fixed_point_c)
+SYM_REF2(days_c, days, hours)
+SYM_REF2(hours_c, hours, minutes)
+SYM_REF2(minutes_c, minutes, seconds)
+SYM_REF2(seconds_c, seconds, milliseconds)
+SYM_REF2(milliseconds_c, milliseconds, unused)
+
+
+/************************************/
+/* B 1.2.3.2 - Time of day and Date */
+/************************************/
+SYM_REF2(time_of_day_c, daytime, unused)
+SYM_REF4(daytime_c, day_hour, day_minute, day_second, unused)
+SYM_REF2(date_c, date_literal, unused)
+SYM_REF4(date_literal_c, year, month, day, unused)
+SYM_REF2(date_and_time_c, date_literal, daytime)
+
+
+/**********************/
+/* B.1.3 - Data types */
+/**********************/
+/***********************************/
+/* B 1.3.1 - Elementary Data Types */
+/***********************************/
+SYM_REF0(time_type_name_c)
+SYM_REF0(bool_type_name_c)
+SYM_REF0(sint_type_name_c)
+SYM_REF0(int_type_name_c)
+SYM_REF0(dint_type_name_c)
+SYM_REF0(lint_type_name_c)
+SYM_REF0(usint_type_name_c)
+SYM_REF0(uint_type_name_c)
+SYM_REF0(udint_type_name_c)
+SYM_REF0(ulint_type_name_c)
+SYM_REF0(real_type_name_c)
+SYM_REF0(lreal_type_name_c)
+SYM_REF0(date_type_name_c)
+SYM_REF0(tod_type_name_c)
+SYM_REF0(dt_type_name_c)
+SYM_REF0(byte_type_name_c)
+SYM_REF0(word_type_name_c)
+SYM_REF0(dword_type_name_c)
+SYM_REF0(lword_type_name_c)
+SYM_REF0(string_type_name_c)
+SYM_REF0(wstring_type_name_c)
+
+
+
+/********************************/
+/* B.1.3.2 - Generic data types */
+/********************************/
+
+/********************************/
+/* B 1.3.3 - Derived data types */
+/********************************/
+/* TYPE type_declaration_list END_TYPE */
+SYM_REF2(data_type_declaration_c, type_declaration_list, unused)
+
+/* helper symbol for data_type_declaration */
+SYM_LIST(type_declaration_list_c)
+
+/* simple_type_name ':' simple_spec_init */
+SYM_REF2(simple_type_declaration_c, simple_type_name, simple_spec_init)
+
+
+/* simple_specification ASSIGN constant */
+SYM_REF2(simple_spec_init_c, simple_specification, constant)
+
+/* subrange_type_name ':' subrange_spec_init */
+SYM_REF2(subrange_type_declaration_c, subrange_type_name, subrange_spec_init)
+
+/* subrange_specification ASSIGN signed_integer */
+SYM_REF2(subrange_spec_init_c, subrange_specification, signed_integer)
+
+/* integer_type_name '(' subrange')' */
+SYM_REF2(subrange_specification_c, integer_type_name, subrange)
+
+/* signed_integer DOTDOT signed_integer */
+SYM_REF2(subrange_c, lower_limit, upper_limit)
+
+/* enumerated_type_name ':' enumerated_spec_init */
+SYM_REF2(enumerated_type_declaration_c, enumerated_type_name, enumerated_spec_init)
+
+/* enumerated_specification ASSIGN enumerated_value */
+SYM_REF2(enumerated_spec_init_c, enumerated_specification, enumerated_value)
+
+/* helper symbol for enumerated_specification->enumerated_spec_init */
+/* enumerated_value_list ',' enumerated_value */
+SYM_LIST(enumerated_value_list_c)
+
+/* enumerated_type_name '#' identifier */
+SYM_REF2(enumerated_value_c, type, value)
+
+/* identifier ':' array_spec_init */
+SYM_REF2(array_type_declaration_c, identifier, array_spec_init)
+
+/* array_specification [ASSIGN array_initialization} */
+/* array_initialization may be NULL ! */
+SYM_REF2(array_spec_init_c, array_specification, array_initialization)
+
+/* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */
+SYM_REF2(array_specification_c, array_subrange_list, non_generic_type_name)
+
+/* helper symbol for array_specification */
+/* array_subrange_list ',' subrange */
+SYM_LIST(array_subrange_list_c)
+
+/* array_initialization: '[' array_initial_elements_list ']' */
+/* helper symbol for array_initialization */
+/* array_initial_elements_list ',' array_initial_elements */
+SYM_LIST(array_initial_elements_list_c)
+
+/* integer '(' [array_initial_element] ')' */
+/* array_initial_element may be NULL ! */
+SYM_REF2(array_initial_elements_c, integer, array_initial_element)
+
+/* structure_type_name ':' structure_specification */
+SYM_REF2(structure_type_declaration_c, structure_type_name, structure_specification)
+
+/* structure_type_name ASSIGN structure_initialization */
+/* structure_initialization may be NULL ! */
+SYM_REF2(initialized_structure_c, structure_type_name, structure_initialization)
+
+/* helper symbol for structure_declaration */
+/* structure_declaration: STRUCT structure_element_declaration_list END_STRUCT */
+/* structure_element_declaration_list structure_element_declaration ';' */
+SYM_LIST(structure_element_declaration_list_c)
+
+/* structure_element_name ':' *_spec_init */
+SYM_REF2(structure_element_declaration_c, structure_element_name, spec_init)
+
+/* helper symbol for structure_initialization */
+/* structure_initialization: '(' structure_element_initialization_list ')' */
+/* structure_element_initialization_list ',' structure_element_initialization */
+SYM_LIST(structure_element_initialization_list_c)
+
+/* structure_element_name ASSIGN value */
+SYM_REF2(structure_element_initialization_c, structure_element_name, value)
+
+/* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */
+/*
+ * NOTE:
+ * (Summary: Contrary to what is expected, the
+ * string_type_declaration_c is not used to store
+ * simple string type declarations that do not include
+ * size limits.
+ * For e.g.:
+ * str1_type: STRING := "hello!"
+ * will be stored in a simple_type_declaration_c
+ * instead of a string_type_declaration_c.
+ * The following:
+ * str2_type: STRING [64] := "hello!"
+ * will be stored in a sring_type_declaration_c
+ *
+ * Read on for why this is done...
+ * End Summary)
+ *
+ * According to the spec, the valid construct
+ * TYPE new_str_type : STRING := "hello!"; END_TYPE
+ * has two possible routes to type_declaration...
+ *
+ * Route 1:
+ * type_declaration: single_element_type_declaration
+ * single_element_type_declaration: simple_type_declaration
+ * simple_type_declaration: identifier ':' simple_spec_init
+ * simple_spec_init: simple_specification ASSIGN constant
+ * (shift: identifier <- 'new_str_type')
+ * simple_specification: elementary_type_name
+ * elementary_type_name: STRING
+ * (shift: elementary_type_name <- STRING)
+ * (reduce: simple_specification <- elementary_type_name)
+ * (shift: constant <- "hello!")
+ * (reduce: simple_spec_init: simple_specification ASSIGN constant)
+ * (reduce: ...)
+ *
+ *
+ * Route 2:
+ * type_declaration: string_type_declaration
+ * string_type_declaration: identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init
+ * (shift: identifier <- 'new_str_type')
+ * elementary_string_type_name: STRING
+ * (shift: elementary_string_type_name <- STRING)
+ * (shift: string_type_declaration_size <- empty )
+ * string_type_declaration_init: ASSIGN character_string
+ * (shift: character_string <- "hello!")
+ * (reduce: string_type_declaration_init <- ASSIGN character_string)
+ * (reduce: string_type_declaration <- identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init )
+ * (reduce: type_declaration <- string_type_declaration)
+ *
+ *
+ * At first glance it seems that removing route 1 would make
+ * the most sense. Unfortunately the construct 'simple_spec_init'
+ * shows up multiple times in other rules, so changing this construct
+ * would also mean changing all the rules in which it appears.
+ * I (Mario) therefore chose to remove route 2 instead. This means
+ * that the above declaration gets stored in a
+ * simple_type_declaration_c, and not in a string_type_declaration_c
+ * as would be expected!
+ */
+/* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */
+SYM_REF4(string_type_declaration_c, string_type_name,
+ elementary_string_type_name,
+ string_type_declaration_size,
+ string_type_declaration_init) /* may be == NULL! */
+
+
+/*********************/
+/* B 1.4 - Variables */
+/*********************/
+SYM_REF2(symbolic_variable_c, var_name, unused)
+
+/********************************************/
+/* B.1.4.1 Directly Represented Variables */
+/********************************************/
+SYM_TOKEN(direct_variable_c)
+
+/*************************************/
+/* B.1.4.2 Multi-element Variables */
+/*************************************/
+/* subscripted_variable '[' subscript_list ']' */
+SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
+
+/* subscript_list ',' subscript */
+SYM_LIST(subscript_list_c)
+
+/* record_variable '.' field_selector */
+/* WARNING: input and/or output variables of function blocks
+ * may be accessed as fields of a tructured variable!
+ * Code handling a structured_variable_c must take
+ * this into account!
+ */
+SYM_REF2(structured_variable_c, record_variable, field_selector)
+
+/******************************************/
+/* B 1.4.3 - Declaration & Initialisation */
+/******************************************/
+SYM_REF0(constant_option_c)
+SYM_REF0(retain_option_c)
+SYM_REF0(non_retain_option_c)
+
+/* option -> the RETAIN/NON_RETAIN/ directive... */
+SYM_REF2(input_declarations_c, option, input_declaration_list)
+
+/* helper symbol for input_declarations */
+SYM_LIST(input_declaration_list_c)
+
+/* edge -> The F_EDGE or R_EDGE directive */
+SYM_REF2(edge_declaration_c, edge, var1_list)
+
+SYM_REF0(raising_edge_option_c)
+SYM_REF0(falling_edge_option_c)
+
+/* spec_init is one of the following...
+ * simple_spec_init_c *
+ * subrange_spec_init_c *
+ * enumerated_spec_init_c *
+ */
+SYM_REF2(var1_init_decl_c, var1_list, spec_init)
+
+/* | var1_list ',' variable_name */
+SYM_LIST(var1_list_c)
+
+/* var1_list ':' array_spec_init */
+SYM_REF2(array_var_init_decl_c, var1_list, array_spec_init)
+
+/* var1_list ':' initialized_structure */
+SYM_REF2(structured_var_init_decl_c, var1_list, initialized_structure)
+
+/* fb_name_list ':' function_block_type_name ASSIGN structure_initialization */
+/* structure_initialization -> may be NULL ! */
+SYM_REF4(fb_name_decl_c, fb_name_list, function_block_type_name, structure_initialization, unused)
+
+/* fb_name_list ',' fb_name */
+SYM_LIST(fb_name_list_c)
+
+/* VAR_OUTPUT [RETAIN | NON_RETAIN] var_init_decl_list END_VAR */
+/* option -> may be NULL ! */
+SYM_REF2(output_declarations_c, option, var_init_decl_list)
+
+/* VAR_IN_OUT var_declaration_list END_VAR */
+SYM_REF2(input_output_declarations_c, var_declaration_list, unused)
+
+/* helper symbol for input_output_declarations */
+/* var_declaration_list var_declaration ';' */
+SYM_LIST(var_declaration_list_c)
+
+/* var1_list ':' array_specification */
+SYM_REF2(array_var_declaration_c, var1_list, array_specification)
+
+/* var1_list ':' structure_type_name */
+SYM_REF2(structured_var_declaration_c, var1_list, structure_type_name)
+
+/* VAR [CONSTANT] var_init_decl_list END_VAR */
+/* option -> may be NULL ! */
+SYM_REF2(var_declarations_c, option, var_init_decl_list)
+
+/* VAR RETAIN var_init_decl_list END_VAR */
+SYM_REF2(retentive_var_declarations_c, var_init_decl_list, unused)
+
+/* VAR [CONSTANT|RETAIN|NON_RETAIN] located_var_decl_list END_VAR */
+/* option -> may be NULL ! */
+SYM_REF2(located_var_declarations_c, option, located_var_decl_list)
+
+/* helper symbol for located_var_declarations */
+/* located_var_decl_list located_var_decl ';' */
+SYM_LIST(located_var_decl_list_c)
+
+/* [variable_name] location ':' located_var_spec_init */
+/* variable_name -> may be NULL ! */
+SYM_REF4(located_var_decl_c, variable_name, location, located_var_spec_init, unused)
+
+/*| VAR_EXTERNAL [CONSTANT] external_declaration_list END_VAR */
+/* option -> may be NULL ! */
+SYM_REF2(external_var_declarations_c, option, external_declaration_list)
+
+/* helper symbol for external_var_declarations */
+/*| external_declaration_list external_declaration';' */
+SYM_LIST(external_declaration_list_c)
+
+/* global_var_name ':' (simple_specification|subrange_specification|enumerated_specification|array_specification|prev_declared_structure_type_name|function_block_type_name */
+SYM_REF2(external_declaration_c, global_var_name, specification)
+
+/*| VAR_GLOBAL [CONSTANT|RETAIN] global_var_decl_list END_VAR */
+/* option -> may be NULL ! */
+SYM_REF2(global_var_declarations_c, option, global_var_decl_list)
+
+/* helper symbol for global_var_declarations */
+/*| global_var_decl_list global_var_decl ';' */
+SYM_LIST(global_var_decl_list_c)
+
+/*| global_var_spec ':' [located_var_spec_init|function_block_type_name] */
+/* type_specification ->may be NULL ! */
+SYM_REF2(global_var_decl_c, global_var_spec, type_specification)
+
+/*| global_var_name location */
+SYM_REF2(global_var_spec_c, global_var_name, location)
+
+/* AT direct_variable */
+SYM_REF2(location_c, direct_variable, unused)
+
+/*| global_var_list ',' global_var_name */
+SYM_LIST(global_var_list_c)
+
+/* var1_list ':' single_byte_string_spec */
+SYM_REF2(single_byte_string_var_declaration_c, var1_list, single_byte_string_spec)
+
+/* STRING ['[' integer ']'] [ASSIGN single_byte_character_string] */
+/* integer ->may be NULL ! */
+/* single_byte_character_string ->may be NULL ! */
+SYM_REF2(single_byte_string_spec_c, integer, single_byte_character_string)
+
+/* var1_list ':' double_byte_string_spec */
+SYM_REF2(double_byte_string_var_declaration_c, var1_list, double_byte_string_spec)
+
+/* WSTRING ['[' integer ']'] [ASSIGN double_byte_character_string] */
+/* integer ->may be NULL ! */
+/* double_byte_character_string ->may be NULL ! */
+SYM_REF2(double_byte_string_spec_c, integer, double_byte_character_string)
+
+/*| VAR [RETAIN|NON_RETAIN] incompl_located_var_decl_list END_VAR */
+/* option ->may be NULL ! */
+SYM_REF2(incompl_located_var_declarations_c, option, incompl_located_var_decl_list)
+
+/* helper symbol for incompl_located_var_declarations */
+/*| incompl_located_var_decl_list incompl_located_var_decl ';' */
+SYM_LIST(incompl_located_var_decl_list_c)
+
+/* variable_name incompl_location ':' var_spec */
+SYM_REF4(incompl_located_var_decl_c, variable_name, incompl_location, var_spec, unused)
+
+/* AT incompl_location_token */
+SYM_TOKEN(incompl_location_c)
+
+/* intermediate helper symbol for:
+ * - non_retentive_var_decls
+ * - output_declarations
+ */
+SYM_LIST(var_init_decl_list_c)
+
+
+
+
+/**************************************/
+/* B.1.5 - Program organization units */
+/**************************************/
+/***********************/
+/* B 1.5.1 - Functions */
+/***********************/
+SYM_REF4(function_declaration_c, derived_function_name, type_name, var_declarations_list, function_body)
+
+/* intermediate helper symbol for
+ * - function_declaration
+ * - function_block_declaration
+ * - program_declaration
+ */
+SYM_LIST(var_declarations_list_c)
+
+/* option -> storage method, CONSTANT or */
+SYM_REF2(function_var_decls_c, option, decl_list)
+
+/* intermediate helper symbol for function_var_decls */
+SYM_LIST(var2_init_decl_list_c)
+
+
+/*****************************/
+/* B 1.5.2 - Function Blocks */
+/*****************************/
+/* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
+SYM_REF4(function_block_declaration_c, fblock_name, var_declarations, fblock_body, unused)
+
+/* intermediate helper symbol for function_declaration */
+/* { io_var_declarations | other_var_declarations } */
+/*
+ * NOTE: we re-use the var_declarations_list_c
+ */
+
+/* VAR_TEMP temp_var_decl_list END_VAR */
+SYM_REF2(temp_var_decls_c, var_decl_list, unused)
+
+/* intermediate helper symbol for temp_var_decls */
+SYM_LIST(temp_var_decls_list_c)
+
+/* VAR NON_RETAIN var_init_decl_list END_VAR */
+SYM_REF2(non_retentive_var_decls_c, var_decl_list, unused)
+
+
+/**********************/
+/* B 1.5.3 - Programs */
+/**********************/
+/* PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */
+SYM_REF4(program_declaration_c, program_type_name, var_declarations, function_block_body, unused)
+
+/* intermediate helper symbol for program_declaration_c */
+/* { io_var_declarations | other_var_declarations } */
+/*
+ * NOTE: we re-use the var_declarations_list_c
+ */
+
+
+
+/*********************************************/
+/* B.1.6 Sequential function chart elements */
+/*********************************************/
+
+
+/********************************/
+/* B 1.7 Configuration elements */
+/********************************/
+
+/*
+CONFIGURATION configuration_name
+ optional_global_var_declarations
+ (resource_declaration_list | single_resource_declaration)
+ optional_access_declarations
+ optional_instance_specific_initializations
+END_CONFIGURATION
+*/
+SYM_REF6(configuration_declaration_c, configuration_name, global_var_declarations, resource_declarations, access_declarations, instance_specific_initializations, unused)
+
+/* helper symbol for configuration_declaration */
+SYM_LIST(resource_declaration_list_c)
+
+/*
+RESOURCE resource_name ON resource_type_name
+ optional_global_var_declarations
+ single_resource_declaration
+END_RESOURCE
+*/
+SYM_REF4(resource_declaration_c, resource_name, resource_type_name, global_var_declarations, resource_declaration)
+
+/* task_configuration_list program_configuration_list */
+SYM_REF2(single_resource_declaration_c, task_configuration_list, program_configuration_list)
+
+/* helper symbol for single_resource_declaration */
+SYM_LIST(task_configuration_list_c)
+
+/* helper symbol for single_resource_declaration */
+SYM_LIST(program_configuration_list_c)
+
+/* helper symbol for
+ * - access_path
+ * - instance_specific_init
+ */
+SYM_LIST(any_fb_name_list_c)
+
+/* [resource_name '.'] global_var_name ['.' structure_element_name] */
+SYM_REF4(global_var_reference_c, resource_name, global_var_name, structure_element_name, unused)
+
+/* prev_declared_program_name '.' symbolic_variable */
+SYM_REF2(program_output_reference_c, program_name, symbolic_variable)
+
+/* TASK task_name task_initialization */
+SYM_REF2(task_configuration_c, task_name, task_initialization)
+
+/* '(' [SINGLE ASSIGN data_source ','] [INTERVAL ASSIGN data_source ','] PRIORITY ASSIGN integer ')' */
+SYM_REF4(task_initialization_c, single_data_source, interval_data_source, priority_data_source, unused)
+
+/* PROGRAM [RETAIN | NON_RETAIN] program_name [WITH task_name] ':' program_type_name ['(' prog_conf_elements ')'] */
+SYM_REF6(program_configuration_c, retain_option, program_name, task_name, program_type_name, prog_conf_elements, unused)
+
+/* prog_conf_elements ',' prog_conf_element */
+SYM_LIST(prog_conf_elements_c)
+
+/* fb_name WITH task_name */
+SYM_REF2(fb_task_c, fb_name, task_name)
+
+/* any_symbolic_variable ASSIGN prog_data_source */
+SYM_REF2(prog_cnxn_assign_c, symbolic_variable, prog_data_source)
+
+/* any_symbolic_variable SENDTO data_sink */
+SYM_REF2(prog_cnxn_sendto_c, symbolic_variable, prog_data_source)
+
+/* VAR_CONFIG instance_specific_init_list END_VAR */
+SYM_REF2(instance_specific_initializations_c, instance_specific_init_list, unused)
+
+/* helper symbol for instance_specific_initializations */
+SYM_LIST(instance_specific_init_list_c)
+
+/* resource_name '.' program_name '.' {fb_name '.'}
+ ((variable_name [location] ':' located_var_spec_init) | (fb_name ':' fb_initialization))
+*/
+SYM_REF6(instance_specific_init_c, resource_name, program_name, any_fb_name_list, variable_name, location, initialization)
+
+/* helper symbol for instance_specific_init */
+/* function_block_type_name ':=' structure_initialization */
+SYM_REF2(fb_initialization_c, function_block_type_name, structure_initialization)
+
+
+
+/****************************************/
+/* B.2 - Language IL (Instruction List) */
+/****************************************/
+/***********************************/
+/* B 2.1 Instructions and Operands */
+/***********************************/
+/*| instruction_list il_instruction */
+SYM_LIST(instruction_list_c)
+
+/* | label ':' [il_incomplete_instruction] eol_list */
+SYM_REF2(il_instruction_c, label, il_instruction)
+
+
+/* | il_simple_operator [il_operand] */
+SYM_REF2(il_simple_operation_c, il_simple_operator, il_operand)
+
+/* | function_name [il_operand_list] */
+SYM_REF2(il_function_call_c, function_name, il_operand_list)
+
+
+/* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */
+SYM_REF4(il_expression_c, il_expr_operator, il_operand, simple_instr_list, unused)
+
+/* il_jump_operator label */
+SYM_REF2(il_jump_operation_c, il_jump_operator, label)
+
+/* il_call_operator prev_declared_fb_name
+ * | il_call_operator prev_declared_fb_name '(' ')'
+ * | il_call_operator prev_declared_fb_name '(' eol_list ')'
+ * | il_call_operator prev_declared_fb_name '(' il_operand_list ')'
+ * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')'
+ */
+SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list)
+
+
+/* | function_name '(' eol_list [il_param_list] ')' */
+SYM_REF2(il_formal_funct_call_c, function_name, il_param_list)
+
+/* | il_operand_list ',' il_operand */
+SYM_LIST(il_operand_list_c)
+
+/* | simple_instr_list il_simple_instruction */
+SYM_LIST(simple_instr_list_c)
+
+/* | il_initial_param_list il_param_instruction */
+SYM_LIST(il_param_list_c)
+
+/* il_assign_operator il_operand
+ * | il_assign_operator '(' eol_list simple_instr_list ')'
+ */
+SYM_REF4(il_param_assignment_c, il_assign_operator, il_operand, simple_instr_list, unused)
+
+/* il_assign_out_operator variable */
+SYM_REF2(il_param_out_assignment_c, il_assign_out_operator, variable)
+
+
+
+/*******************/
+/* B 2.2 Operators */
+/*******************/
+SYM_REF0(LD_operator_c)
+SYM_REF0(LDN_operator_c)
+SYM_REF0(ST_operator_c)
+SYM_REF0(STN_operator_c)
+SYM_REF0(NOT_operator_c)
+SYM_REF0(S_operator_c)
+SYM_REF0(R_operator_c)
+SYM_REF0(S1_operator_c)
+SYM_REF0(R1_operator_c)
+SYM_REF0(CLK_operator_c)
+SYM_REF0(CU_operator_c)
+SYM_REF0(CD_operator_c)
+SYM_REF0(PV_operator_c)
+SYM_REF0(IN_operator_c)
+SYM_REF0(PT_operator_c)
+SYM_REF0(AND_operator_c)
+SYM_REF0(OR_operator_c)
+SYM_REF0(XOR_operator_c)
+SYM_REF0(ANDN_operator_c)
+SYM_REF0(ORN_operator_c)
+SYM_REF0(XORN_operator_c)
+SYM_REF0(ADD_operator_c)
+SYM_REF0(SUB_operator_c)
+SYM_REF0(MUL_operator_c)
+SYM_REF0(DIV_operator_c)
+SYM_REF0(MOD_operator_c)
+SYM_REF0(GT_operator_c)
+SYM_REF0(GE_operator_c)
+SYM_REF0(EQ_operator_c)
+SYM_REF0(LT_operator_c)
+SYM_REF0(LE_operator_c)
+SYM_REF0(NE_operator_c)
+SYM_REF0(CAL_operator_c)
+SYM_REF0(CALC_operator_c)
+SYM_REF0(CALCN_operator_c)
+SYM_REF0(RET_operator_c)
+SYM_REF0(RETC_operator_c)
+SYM_REF0(RETCN_operator_c)
+SYM_REF0(JMP_operator_c)
+SYM_REF0(JMPC_operator_c)
+SYM_REF0(JMPCN_operator_c)
+
+/*| [NOT] any_identifier SENDTO */
+SYM_REF2(il_assign_out_operator_c, option, variable_name)
+
+
+
+/***************************************/
+/* B.3 - Language ST (Structured Text) */
+/***************************************/
+/***********************/
+/* B 3.1 - Expressions */
+/***********************/
+SYM_REF2(or_expression_c, l_exp, r_exp)
+SYM_REF2(xor_expression_c, l_exp, r_exp)
+SYM_REF2(and_expression_c, l_exp, r_exp)
+SYM_REF2(equ_expression_c, l_exp, r_exp)
+SYM_REF2(notequ_expression_c, l_exp, r_exp)
+SYM_REF2(lt_expression_c, l_exp, r_exp)
+SYM_REF2(gt_expression_c, l_exp, r_exp)
+SYM_REF2(le_expression_c, l_exp, r_exp)
+SYM_REF2(ge_expression_c, l_exp, r_exp)
+SYM_REF2(add_expression_c, l_exp, r_exp)
+SYM_REF2(sub_expression_c, l_exp, r_exp)
+SYM_REF2(mul_expression_c, l_exp, r_exp)
+SYM_REF2(div_expression_c, l_exp, r_exp)
+SYM_REF2(mod_expression_c, l_exp, r_exp)
+SYM_REF2(power_expression_c, l_exp, r_exp)
+SYM_REF2(neg_expression_c, exp, unused)
+SYM_REF2(not_expression_c, exp, unused)
+
+SYM_REF2(function_invocation_c, function_name, parameter_assignment_list)
+
+
+/********************/
+/* B 3.2 Statements */
+/********************/
+SYM_LIST(statement_list_c)
+
+
+/*********************************/
+/* B 3.2.1 Assignment Statements */
+/*********************************/
+SYM_REF2(assignment_statement_c, l_exp, r_exp)
+
+
+/*****************************************/
+/* B 3.2.2 Subprogram Control Statements */
+/*****************************************/
+/* RETURN */
+SYM_REF0(return_statement_c)
+
+/* fb_name '(' [param_assignment_list] ')' */
+/* param_assignment_list -> may be NULL ! */
+SYM_REF2(fb_invocation_c, fb_name, param_assignment_list)
+
+/* helper symbol for fb_invocation */
+/* param_assignment_list ',' param_assignment */
+SYM_LIST(param_assignment_list_c)
+
+/* variable_name ASSIGN expression */
+SYM_REF2(input_variable_param_assignment_c, variable_name, expression)
+
+/* [NOT] variable_name '=>' variable */
+SYM_REF4(output_variable_param_assignment_c, not_param, variable_name, variable, unused)
+
+/* helper CLASS for output_variable_param_assignment */
+SYM_REF0(not_paramassign_c)
+
+
+/********************************/
+/* B 3.2.3 Selection Statements */
+/********************************/
+/* IF expression THEN statement_list elseif_statement_list ELSE statement_list END_IF */
+SYM_REF4(if_statement_c, expression, statement_list, elseif_statement_list, else_statement_list)
+
+/* helper symbol for if_statement */
+SYM_LIST(elseif_statement_list_c)
+
+/* helper symbol for elseif_statement_list */
+/* ELSIF expression THEN statement_list */
+SYM_REF2(elseif_statement_c, expression, statement_list)
+
+/* CASE expression OF case_element_list ELSE statement_list END_CASE */
+SYM_REF4(case_statement_c, expression, case_element_list, statement_list, unused)
+
+/* helper symbol for case_statement */
+SYM_LIST(case_element_list_c)
+
+/* case_list ':' statement_list */
+SYM_REF2(case_element_c, case_list, statement_list)
+
+SYM_LIST(case_list_c)
+
+
+/********************************/
+/* B 3.2.4 Iteration Statements */
+/********************************/
+/* FOR control_variable ASSIGN expression TO expression [BY expression] DO statement_list END_FOR */
+SYM_REF6(for_statement_c, control_variable, beg_expression, end_expression, by_expression, statement_list, unused)
+
+/* WHILE expression DO statement_list END_WHILE */
+SYM_REF2(while_statement_c, expression, statement_list)
+
+/* REPEAT statement_list UNTIL expression END_REPEAT */
+SYM_REF2(repeat_statement_c, statement_list, expression)
+
+/* EXIT */
+SYM_REF0(exit_statement_c)
+
+
diff -r 000000000000 -r fb772792efd1 absyntax/absyntax.hh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax/absyntax.hh Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,189 @@
+/*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+/*
+ * Declaration of the Abstract Syntax data structure components
+ */
+
+/*
+ * ABSYNTAX.H
+ *
+ * This generates the parse tree structure used to bind the components
+ * identified by Bison in the correct syntax order. At the end of the
+ * Bison analysis the tree is walked in a sequential fashion generating
+ * the relavent code.
+ */
+
+#ifndef _ABSYNTAX_HH
+#define _ABSYNTAX_HH
+
+
+#include // required for NULL
+
+/* Forward declaration of the visitor interface
+ * dclared in the visitor.hh file
+ * We cannot include the visitor.hh file, as it will
+ * include this same file first, as it too requires references
+ * to the abstract syntax classes defined here.
+ */
+class visitor_c; // forward declaration
+
+
+class symbol_c; // forward declaration
+//extern symbol_c *tree_root;
+
+
+
+/* The base class of all symbols */
+class symbol_c {
+
+ public:
+ /*
+ * Line number for the purposes of error checking
+ */
+ long lineno;
+
+ public:
+ /* default constructor */
+ symbol_c(void);
+ symbol_c(long lineno);
+
+ /* default destructor */
+ /* must be virtual so compiler does not complain... */
+ virtual ~symbol_c(void) {return;};
+
+ virtual void *accept(visitor_c &visitor) {return NULL;};
+};
+
+
+class token_c: public symbol_c {
+ public:
+ /* the value of the symbol. */
+ const char *value;
+
+ public:
+ token_c(const char *value);
+};
+
+
+ /* a list of symbols... */
+class list_c: public symbol_c {
+ public:
+ int n;
+ symbol_c **elements;
+
+ public:
+ list_c(void);
+ list_c(symbol_c *elem);
+ /* insert a new element */
+ virtual void add_element(symbol_c *elem);
+};
+
+
+
+
+#define SYM_LIST(class_name_c) \
+class class_name_c: public list_c { \
+ public: \
+ virtual void *accept(visitor_c &visitor); \
+};
+
+
+#define SYM_TOKEN(class_name_c) \
+class class_name_c: public token_c { \
+ public: \
+ class_name_c(const char *value); \
+ virtual void *accept(visitor_c &visitor); \
+};
+
+
+#define SYM_REF0(class_name_c) \
+class class_name_c: public symbol_c { \
+ public: \
+ virtual void *accept(visitor_c &visitor); \
+};
+
+
+#define SYM_REF2(class_name_c, ref1, ref2) \
+class class_name_c: public symbol_c { \
+ public: \
+ symbol_c *ref1; \
+ symbol_c *ref2; \
+ public: \
+ class_name_c(symbol_c *ref1, \
+ symbol_c *ref2 = NULL); \
+ virtual void *accept(visitor_c &visitor); \
+};
+
+
+#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4) \
+class class_name_c: public symbol_c { \
+ public: \
+ symbol_c *ref1; \
+ symbol_c *ref2; \
+ symbol_c *ref3; \
+ symbol_c *ref4; \
+ public: \
+ class_name_c(symbol_c *ref1, \
+ symbol_c *ref2, \
+ symbol_c *ref3, \
+ symbol_c *ref4 = NULL); \
+ virtual void *accept(visitor_c &visitor); \
+};
+
+
+#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6) \
+class class_name_c: public symbol_c { \
+ public: \
+ symbol_c *ref1; \
+ symbol_c *ref2; \
+ symbol_c *ref3; \
+ symbol_c *ref4; \
+ symbol_c *ref5; \
+ symbol_c *ref6; \
+ public: \
+ class_name_c(symbol_c *ref1, \
+ symbol_c *ref2, \
+ symbol_c *ref3, \
+ symbol_c *ref4, \
+ symbol_c *ref5, \
+ symbol_c *ref6 = NULL); \
+ virtual void *accept(visitor_c &visitor); \
+};
+
+
+#include "absyntax.def"
+
+
+
+#undef SYM_LIST
+#undef SYM_TOKEN
+#undef SYM_REF0
+#undef SYM_REF2
+#undef SYM_REF4
+#undef SYM_REF6
+
+
+
+#endif /* _ABSYNTAX_HH */
diff -r 000000000000 -r fb772792efd1 absyntax/visitor.cc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax/visitor.cc Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,265 @@
+/*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+
+/*
+ * VISITOR.CC
+ *
+ * Three base implementations of the visitor interface,
+ * that may be later extended to execute a particular algorithm.
+ *
+ * The null (class null_visitor_c) does nothing.
+ *
+ * The iterator (class iterator_visitor_c) iterates through
+ * every object in the syntax tree.
+ *
+ * The search class (class search_visitor_c) iterates through
+ * every object, until one returns a value != NULL.
+ */
+
+
+
+
+
+#include
+
+#include /* required for NULL */
+#include "visitor.hh"
+
+#include
+
+
+/******************/
+/* visitor_c */
+/******************/
+
+visitor_c::~visitor_c(void) {return;}
+
+
+/******************/
+/* null_visitor_c */
+/******************/
+
+null_visitor_c::~null_visitor_c(void) {return;}
+
+#define SYM_LIST(class_name_c) \
+ void *null_visitor_c::visit(class_name_c *symbol) {return NULL;}
+
+#define SYM_TOKEN(class_name_c) \
+ void *null_visitor_c::visit(class_name_c *symbol) {return NULL;}
+
+#define SYM_REF0(class_name_c) \
+ void *null_visitor_c::visit(class_name_c *symbol) {return NULL;}
+
+#define SYM_REF2(class_name_c, ref1, ref2) \
+ void *null_visitor_c::visit(class_name_c *symbol) {return NULL;}
+
+#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4) \
+ void *null_visitor_c::visit(class_name_c *symbol) {return NULL;}
+
+#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6) \
+ void *null_visitor_c::visit(class_name_c *symbol) {return NULL;}
+
+
+#include "absyntax.def"
+
+
+
+
+#undef SYM_LIST
+#undef SYM_TOKEN
+#undef SYM_REF0
+#undef SYM_REF2
+#undef SYM_REF4
+#undef SYM_REF6
+
+
+
+
+
+
+/**********************/
+/* iterator_visitor_c */
+/**********************/
+
+iterator_visitor_c::~iterator_visitor_c(void) {return;}
+
+
+void *iterator_visitor_c::visit_list(list_c *list) {
+ for(int i = 0; i < list->n; i++) {
+ list->elements[i]->accept(*this);
+ }
+ return NULL;
+}
+
+
+#define SYM_LIST(class_name_c) \
+ void *iterator_visitor_c::visit(class_name_c *symbol) {return visit_list(symbol);}
+
+#define SYM_TOKEN(class_name_c) \
+ void *iterator_visitor_c::visit(class_name_c *symbol) {return NULL;}
+
+#define SYM_REF0(class_name_c) \
+ void *iterator_visitor_c::visit(class_name_c *symbol) {return NULL;}
+
+#define SYM_REF2(class_name_c, ref1, ref2) \
+void *iterator_visitor_c::visit(class_name_c *symbol) { \
+ if (symbol->ref1!=NULL) symbol->ref1->accept(*this); \
+ if (symbol->ref2!=NULL) symbol->ref2->accept(*this); \
+ return NULL; \
+}
+
+#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4) \
+void *iterator_visitor_c::visit(class_name_c *symbol) { \
+ if (symbol->ref1) symbol->ref1->accept(*this); \
+ if (symbol->ref2) symbol->ref2->accept(*this); \
+ if (symbol->ref3) symbol->ref3->accept(*this); \
+ if (symbol->ref4) symbol->ref4->accept(*this); \
+ return NULL; \
+}
+
+
+#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6) \
+void *iterator_visitor_c::visit(class_name_c *symbol) { \
+ if (symbol->ref1) symbol->ref1->accept(*this); \
+ if (symbol->ref2) symbol->ref2->accept(*this); \
+ if (symbol->ref3) symbol->ref3->accept(*this); \
+ if (symbol->ref4) symbol->ref4->accept(*this); \
+ if (symbol->ref5) symbol->ref5->accept(*this); \
+ if (symbol->ref6) symbol->ref6->accept(*this); \
+ return NULL; \
+}
+
+
+
+#include "absyntax.def"
+
+
+
+#undef SYM_LIST
+#undef SYM_TOKEN
+#undef SYM_REF0
+#undef SYM_REF2
+#undef SYM_REF4
+#undef SYM_REF6
+
+
+
+
+
+
+
+
+
+
+/********************/
+/* search_visitor_c */
+/********************/
+
+search_visitor_c::~search_visitor_c(void) {return;}
+
+
+void *search_visitor_c::visit_list(list_c *list) {
+ for(int i = 0; i < list->n; i++) {
+ void *res = list->elements[i]->accept(*this);
+ if (res != NULL)
+ return res;
+ }
+ return NULL;
+}
+
+
+#define SYM_LIST(class_name_c) \
+ void *search_visitor_c::visit(class_name_c *symbol) {return visit_list(symbol);}
+
+#define SYM_TOKEN(class_name_c) \
+ void *search_visitor_c::visit(class_name_c *symbol) {return NULL;}
+
+#define SYM_REF0(class_name_c) \
+ void *search_visitor_c::visit(class_name_c *symbol) {return NULL;}
+
+#define SYM_REF2(class_name_c, ref1, ref2) \
+void *search_visitor_c::visit(class_name_c *symbol) { \
+ void *res = NULL; \
+ if (symbol->ref1) res = symbol->ref1->accept(*this); \
+ if (res != NULL) return res; \
+ if (symbol->ref2) return symbol->ref2->accept(*this); \
+ return NULL; \
+}
+
+#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4) \
+void *search_visitor_c::visit(class_name_c *symbol) { \
+ void *res = NULL; \
+ if (symbol->ref1) res = symbol->ref1->accept(*this); \
+ if (res != NULL) return res; \
+ if (symbol->ref2) res = symbol->ref2->accept(*this); \
+ if (res != NULL) return res; \
+ if (symbol->ref3) res = symbol->ref3->accept(*this); \
+ if (res != NULL) return res; \
+ if (symbol->ref4) return symbol->ref4->accept(*this); \
+ return NULL; \
+}
+
+
+#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6) \
+void *search_visitor_c::visit(class_name_c *symbol) { \
+ void *res = NULL; \
+ if (symbol->ref1) res = symbol->ref1->accept(*this); \
+ if (res != NULL) return res; \
+ if (symbol->ref2) res = symbol->ref2->accept(*this); \
+ if (res != NULL) return res; \
+ if (symbol->ref3) res = symbol->ref3->accept(*this); \
+ if (res != NULL) return res; \
+ if (symbol->ref4) res = symbol->ref4->accept(*this); \
+ if (res != NULL) return res; \
+ if (symbol->ref5) res = symbol->ref5->accept(*this); \
+ if (res != NULL) return res; \
+ if (symbol->ref6) return symbol->ref6->accept(*this); \
+ return NULL; \
+}
+
+
+
+#include "absyntax.def"
+
+
+
+#undef SYM_LIST
+#undef SYM_TOKEN
+#undef SYM_REF0
+#undef SYM_REF2
+#undef SYM_REF4
+#undef SYM_REF6
+
+
+
+
+
+
+
+
+
+
+
+
diff -r 000000000000 -r fb772792efd1 absyntax/visitor.hh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax/visitor.hh Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,171 @@
+/*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+
+/*
+ * VISITOR.HH
+ *
+ *
+ * The asbract syntax tree is scaned several times
+ * during the whole compilation process. For e.g., stage 3 verifies
+ * semantics, and stage 4 produces output.
+ *
+ * Since the number of functions that need to scan through
+ * the abtract syntax tree may increase in time, (e.g. new
+ * output formats, new semantic checks, etc...) while the
+ * abstract syntax tree class structure is pretty stable
+ * (i.e. the ST and IL languages will not be changing much...),
+ * we use the 'visitor' design patern.
+ *
+ * It is not strictly necessary to use this pattern, but it does
+ * have the advantage of bringing together the functions
+ * that implement the same algorithm, each on a different
+ * class of object in the abstract syntax tree.
+ *
+ *
+ * This file contains the interface that each visitor class
+ * must implement in order to be able to visit the abstract
+ * syntax tree (class visitor_c)
+ *
+ * Three implementations of this interface are also provided,
+ * that may be later extended to execute a particular algorithm.
+ *
+ * The null (class null_visitor_c) does nothing.
+ *
+ * The iterator (class iterator_visitor_c) iterates through
+ * every object in the syntax tree.
+ *
+ * The search class (class search_visitor_c) iterates through
+ * every object, until one returns a value != NULL.
+ */
+
+
+#ifndef _VISITOR_HH
+#define _VISITOR_HH
+
+
+
+
+#include "absyntax.hh"
+
+
+
+#define SYM_LIST(class_name_c) \
+ virtual void *visit(class_name_c *symbol) = 0;
+
+#define SYM_TOKEN(class_name_c) \
+ virtual void *visit(class_name_c *symbol) = 0;
+
+#define SYM_REF0(class_name_c) \
+ virtual void *visit(class_name_c *symbol) = 0;
+
+#define SYM_REF2(class_name_c, ref1, ref2) \
+ virtual void *visit(class_name_c *symbol) = 0;
+
+#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4) \
+ virtual void *visit(class_name_c *symbol) = 0;
+
+#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6) \
+ virtual void *visit(class_name_c *symbol) = 0;
+
+class visitor_c {
+ public:
+ #include "absyntax.def"
+
+ virtual ~visitor_c(void);
+};
+
+#undef SYM_LIST
+#undef SYM_TOKEN
+#undef SYM_REF0
+#undef SYM_REF2
+#undef SYM_REF4
+#undef SYM_REF6
+
+
+
+
+
+
+#define SYM_LIST(class_name_c) \
+ virtual void *visit(class_name_c *symbol);
+
+#define SYM_TOKEN(class_name_c) \
+ virtual void *visit(class_name_c *symbol);
+
+#define SYM_REF0(class_name_c) \
+ virtual void *visit(class_name_c *symbol);
+
+#define SYM_REF2(class_name_c, ref1, ref2) \
+ virtual void *visit(class_name_c *symbol);
+
+#define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4) \
+ virtual void *visit(class_name_c *symbol);
+
+#define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6) \
+ virtual void *visit(class_name_c *symbol);
+
+
+
+
+
+class null_visitor_c: public visitor_c {
+ public:
+ #include "absyntax.def"
+
+ virtual ~null_visitor_c(void);
+};
+
+
+
+class iterator_visitor_c: public visitor_c {
+ protected:
+ void *visit_list(list_c *list);
+
+ public:
+ #include "absyntax.def"
+
+ virtual ~iterator_visitor_c(void);
+};
+
+
+class search_visitor_c: public visitor_c {
+ protected:
+ void *visit_list(list_c *list);
+
+ public:
+ #include "absyntax.def"
+
+ virtual ~search_visitor_c(void);
+};
+
+
+#undef SYM_LIST
+#undef SYM_TOKEN
+#undef SYM_REF0
+#undef SYM_REF2
+#undef SYM_REF4
+#undef SYM_REF6
+
+#endif /* _VISITOR_HH */
diff -r 000000000000 -r fb772792efd1 lib/bcd_to_int.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/bcd_to_int.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,98 @@
+(*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ *)
+
+(*
+ * This is part of the library conatining the functions
+ * and function blocks defined in the standard.
+ *
+ * Conversion from BCD
+ * -------------------
+ *)
+
+
+
+FUNCTION BYTE_BCD_TO_USINT: USINT
+ VAR_INPUT
+ BCD : BYTE;
+ END_VAR
+
+ BYTE_BCD_TO_USINT := BCD MOD 16;
+ BCD := BCD / 16;
+ BYTE_BCD_TO_USINT := BYTE_BCD_TO_USINT + 10*BCD;
+END_FUNCTION
+
+
+
+
+FUNCTION WORD_BCD_TO_UINT: UINT
+ VAR_INPUT
+ BCD : WORD;
+ END_VAR
+
+ WORD_BCD_TO_UINT := BCD MOD 16;
+ BCD := BCD / 16;
+ WORD_BCD_TO_UINT := WORD_BCD_TO_UINT + 10*(BCD MOD 16);
+ BCD := BCD / 16;
+ WORD_BCD_TO_UINT := WORD_BCD_TO_UINT + 100*(BCD MOD 16);
+ BCD := BCD / 16;
+ WORD_BCD_TO_UINT := WORD_BCD_TO_UINT + 1000*BCD;
+END_FUNCTION
+
+
+
+
+FUNCTION DWORD_BCD_TO_UDINT: UDINT
+ VAR_INPUT
+ BCD : DWORD;
+ END_VAR
+
+ DWORD_BCD_TO_UDINT := BCD MOD 16;
+ BCD := BCD / 16;
+ DWORD_BCD_TO_UDINT := DWORD_BCD_TO_UDINT + 10*(BCD MOD 16);
+ BCD := BCD / 16;
+ DWORD_BCD_TO_UDINT := DWORD_BCD_TO_UDINT + 100*(BCD MOD 16);
+ BCD := BCD / 16;
+ DWORD_BCD_TO_UDINT := DWORD_BCD_TO_UDINT + 1000*(BCD MOD 16);
+ BCD := BCD / 16;
+ DWORD_BCD_TO_UDINT := DWORD_BCD_TO_UDINT + 1_0000*(BCD MOD 16);
+ BCD := BCD / 16;
+ DWORD_BCD_TO_UDINT := DWORD_BCD_TO_UDINT + 10_0000*(BCD MOD 16);
+ BCD := BCD / 16;
+ DWORD_BCD_TO_UDINT := DWORD_BCD_TO_UDINT + 100_0000*(BCD MOD 16);
+ BCD := BCD / 16;
+ DWORD_BCD_TO_UDINT := DWORD_BCD_TO_UDINT + 1000_0000*BCD;
+END_FUNCTION
+
+
+
+
+FUNCTION LWORD_BCD_TO_ULINT: ULINT
+ VAR_INPUT
+ BCD : LWORD;
+ END_VAR
+
+ LWORD_BCD_TO_ULINT := DWORD_BCD_TO_UDINT(BCD MOD (256*256*256*256));
+ BCD := BCD / (256*256*256*256);
+ LWORD_BCD_TO_ULINT := LWORD_BCD_TO_ULINT + 1_0000_0000*DWORD_BCD_TO_UDINT(BCD);
+END_FUNCTION
diff -r 000000000000 -r fb772792efd1 lib/bistable.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/bistable.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,65 @@
+(*
+ * (c) 26 Feb 2001 David Campbell
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ *)
+
+
+(*
+ * This is part of the library conatining the functions
+ * and function blocks defined in the standard.
+ *
+ * SR and RS function blocks
+ * -------------------------
+ *)
+
+
+FUNCTION_BLOCK SR
+ VAR_INPUT
+ S1 : BOOL;
+ R : BOOL;
+ END_VAR
+ VAR_OUTPUT
+ Q1 : BOOL;
+ END_VAR
+ VAR
+ Q_INTERNAL : BOOL;
+ END_VAR
+
+ Q_INTERNAL := S1 OR ( Q_INTERNAL AND (NOT R));
+ Q1 := Q_INTERNAL;
+END_FUNCTION_BLOCK
+
+FUNCTION_BLOCK RS
+ VAR_INPUT
+ S : BOOL;
+ R1 : BOOL;
+ END_VAR
+ VAR_OUTPUT
+ Q1 : BOOL;
+ END_VAR
+ VAR
+ Q_INTERNAL : BOOL;
+ END_VAR
+
+ Q_INTERNAL := (NOT R1) AND (S OR Q_INTERNAL);
+ Q1 := Q_INTERNAL;
+END_FUNCTION_BLOCK
diff -r 000000000000 -r fb772792efd1 lib/counter.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/counter.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,94 @@
+(* Following taken directly from the IEC 61131.3 draft standard *)
+
+(*
+ * An IEC 61131-3 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ *)
+
+
+(*
+ * This is part of the library conatining the functions
+ * and function blocks defined in the standard.
+ *
+ * Counter function blocks
+ * -----------------------
+ *)
+
+
+FUNCTION_BLOCK CTU
+ VAR_INPUT
+ CU : BOOL;
+ R : BOOL;
+ PV : INT;
+ END_VAR
+ VAR_OUTPUT
+ Q : BOOL;
+ CV : INT;
+ END_VAR
+ VAR RETAIN
+ PVmax : INT;
+ END_VAR
+ IF R THEN CV := 0 ;
+ ELSIF CU AND (CV < PVmax)
+ THEN CV := CV+1;
+ END_IF ;
+ Q := (CV >= PV) ;
+END_FUNCTION_BLOCK
+
+
+FUNCTION_BLOCK CTD
+ VAR_INPUT
+ CD : BOOL;
+ LD : BOOL;
+ PV : INT;
+ END_VAR
+ VAR_OUTPUT
+ Q : BOOL;
+ CV : INT;
+ END_VAR
+ VAR RETAIN
+ PVmin : INT;
+ END_VAR
+ IF LD THEN CV := PV ;
+ ELSIF CD AND (CV > PVmin)
+ THEN CV := CV-1;
+ END_IF ;
+ Q := (CV <= 0) ;
+END_FUNCTION_BLOCK
+
+
+FUNCTION_BLOCK CTUD
+ VAR_INPUT
+ CU : BOOL;
+ CD : BOOL;
+ R : BOOL;
+ LD : BOOL;
+ PV : INT;
+ END_VAR
+ VAR_OUTPUT
+ QU : BOOL;
+ QD : BOOL;
+ CV : INT;
+ END_VAR
+ VAR RETAIN
+ PVmax : INT;
+ PVmin : INT;
+ END_VAR
+ IF R THEN CV := 0 ;
+ ELSIF LD THEN CV := PV ;
+ ELSE
+ IF NOT (CU AND CD) THEN
+ IF CU AND (CV < PVmax)
+ THEN CV := CV+1;
+ ELSIF CD AND (CV > PVmin)
+ THEN CV := CV-1;
+ END_IF;
+ END_IF;
+ END_IF ;
+ QU := (CV >= PV) ;
+ QD := (CV <= 0) ;
+END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 lib/edge_detection.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/edge_detection.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,35 @@
+(* Following taken directly from the IEC 61131.3 draft standard *)
+
+(*
+ * An IEC 61131-3 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ *)
+
+
+(*
+ * This is part of the library conatining the functions
+ * and function blocks defined in the standard.
+ *
+ * Edge detection function blocks
+ * ------------------------------
+ *)
+
+FUNCTION_BLOCK R_TRIG
+ VAR_INPUT CLK: BOOL; END_VAR
+ VAR_OUTPUT Q: BOOL; END_VAR
+ VAR RETAIN M: BOOL; END_VAR
+Q := CLK AND NOT M;
+M := CLK;
+END_FUNCTION_BLOCK
+
+FUNCTION_BLOCK F_TRIG
+ VAR_INPUT CLK: BOOL; END_VAR
+ VAR_OUTPUT Q: BOOL; END_VAR
+ VAR RETAIN M: BOOL; END_VAR
+Q := NOT CLK AND NOT M;
+M := NOT CLK;
+END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 lib/ieclib.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/ieclib.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,36 @@
+(*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ *)
+
+(*
+ * This is the library conatining the functions
+ * and function blocks defined in the standard.
+ *)
+
+{#include "bcd_to_int.txt" }
+{#include "int_to_bcd.txt" }
+{#include "edge_detection.txt" }
+{#include "bistable.txt" }
+{#include "counter.txt" }
+{#include "timer.txt" }
+{#include "time_math.txt" }
diff -r 000000000000 -r fb772792efd1 lib/int_to_bcd.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/int_to_bcd.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,117 @@
+(*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ *)
+
+(*
+ * This is part of the library conatining the functions
+ * and function blocks defined in the standard.
+ *
+ * Conversion to BCD
+ * -----------------
+ *)
+
+
+
+
+FUNCTION USINT_TO_BCD_BYTE: BYTE
+ VAR_INPUT
+ VALUE : USINT;
+ END_VAR
+
+ USINT_TO_BCD_BYTE := VALUE MOD 10;
+ VALUE := VALUE / 10;
+ USINT_TO_BCD_BYTE := USINT_TO_BCD_BYTE + 16*VALUE;
+ IF VALUE > 9
+ THEN
+ (* The standard is silent on how to handle overflows!! *)
+ (* We simply set it to the highets value! *)
+ USINT_TO_BCD_BYTE := 16#99;
+ END_IF;
+END_FUNCTION
+
+
+
+
+FUNCTION UINT_TO_BCD_WORD: WORD
+ VAR_INPUT
+ VALUE : UINT;
+ END_VAR
+
+ UINT_TO_BCD_WORD := VALUE MOD 10;
+ VALUE := VALUE / 10;
+ UINT_TO_BCD_WORD := UINT_TO_BCD_WORD + 16*(VALUE MOD 10);
+ VALUE := VALUE / 10;
+ UINT_TO_BCD_WORD := UINT_TO_BCD_WORD + 16*16*(VALUE MOD 10);
+ VALUE := VALUE / 10;
+ UINT_TO_BCD_WORD := UINT_TO_BCD_WORD + 16*16*16*VALUE;
+ IF VALUE > 9
+ THEN
+ (* The standard is silent on how to handle overflows!! *)
+ (* We simply set it to the highets value! *)
+ UINT_TO_BCD_WORD := 16#9999;
+ END_IF;
+END_FUNCTION
+
+
+
+
+FUNCTION UDINT_TO_BCD_DWORD: DWORD
+ VAR_INPUT
+ VALUE : UINT;
+ END_VAR
+
+ UDINT_TO_BCD_DWORD := VALUE MOD 16;
+ VALUE := VALUE / 10;
+ UDINT_TO_BCD_DWORD := UDINT_TO_BCD_DWORD + 16*(VALUE MOD 10);
+ VALUE := VALUE / 10;
+ UDINT_TO_BCD_DWORD := UDINT_TO_BCD_DWORD + 256*(VALUE MOD 10);
+ VALUE := VALUE / 10;
+ UDINT_TO_BCD_DWORD := UDINT_TO_BCD_DWORD + 16*256*(VALUE MOD 10);
+ VALUE := VALUE / 10;
+ UDINT_TO_BCD_DWORD := UDINT_TO_BCD_DWORD + 256*256*(VALUE MOD 10);
+ VALUE := VALUE / 10;
+ UDINT_TO_BCD_DWORD := UDINT_TO_BCD_DWORD + 16*256*256*(VALUE MOD 10);
+ VALUE := VALUE / 10;
+ UDINT_TO_BCD_DWORD := UDINT_TO_BCD_DWORD + 256*256*256*(VALUE MOD 10);
+ VALUE := VALUE / 10;
+ UDINT_TO_BCD_DWORD := UDINT_TO_BCD_DWORD + 16*256*256*256*VALUE;
+ IF VALUE > 9
+ THEN
+ (* The standard is silent on how to handle overflows!! *)
+ (* We simply set it to the highest value! *)
+ UDINT_TO_BCD_DWORD := 16#9999_9999;
+ END_IF;
+END_FUNCTION
+
+
+
+
+FUNCTION ULINT_TO_BCD_LWORD: LWORD
+ VAR_INPUT
+ VALUE : UINT;
+ END_VAR
+
+ ULINT_TO_BCD_LWORD := UDINT_TO_BCD_DWORD(VALUE MOD 1_0000_0000);
+ VALUE := VALUE / 1_0000_0000;
+ ULINT_TO_BCD_LWORD := ULINT_TO_BCD_LWORD + 256*256*256*256*UDINT_TO_BCD_DWORD(VALUE);
+END_FUNCTION
diff -r 000000000000 -r fb772792efd1 lib/ramp_st.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/ramp_st.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,25 @@
+ FUNCTION_BLOCK RAMP
+ VAR_INPUT
+ RUN : BOOL ; (* 0 - track X0, 1 - ramp to/track X1 *)
+ X0,X1 : REAL ;
+ TR : TIME ; (* Ramp duration *)
+ CYCLE : TIME ; (* Sampling period *)
+ END_VAR
+ VAR_OUTPUT
+ BUSY : BOOL ; (* BUSY = 1 during ramping period *)
+ XOUT : REAL := 0.0 ;
+ END_VAR
+ VAR XI : REAL ; (* Initial value *)
+ T : TIME := T#0s; (* Elapsed time of ramp *)
+ END_VAR
+ BUSY := RUN ;
+ IF RUN THEN
+ IF T >= TR THEN BUSY := 0 ; XOUT := X1 ;
+ ELSE XOUT := XI + (X1-XI) * TIME_TO_REAL(T)
+ / TIME_TO_REAL(TR) ;
+ T := T + CYCLE ;
+ END_IF ;
+ ELSE XOUT := X0 ; XI := X0 ; T := t#0s ;
+ END_IF ;
+ END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 lib/time_math.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/time_math.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,360 @@
+(*
+ * (c) 2005 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ *)
+
+(*
+ * This is part of the library conatining the functions
+ * and function blocks defined in the standard.
+ *
+ * Math functions on Time and Date data types.
+ * -------------------------------------------
+ *
+ * We also include the two data type conversions defined in table 30 of the IEC 61131-3 standard (version
+ *)
+
+
+(* NOTE: The IEC 61131-3 standard library includes overloaded functions, which are not
+ * allowed in user code. Since our compiler does not yet support overloaded functions, these
+ * are commented out in the following library for the moment...
+ *)
+
+(***************)
+(* TIME + TIME *)
+(***************)
+
+FUNCTION ADD : TIME
+ VAR_INPUT
+ IN1 : TIME;
+ IN2 : TIME;
+ END_VAR
+
+ ADD := IN1 + IN2;
+END_FUNCTION
+
+
+FUNCTION ADD_TIME : TIME
+ VAR_INPUT
+ IN1 : TIME;
+ IN2 : TIME;
+ END_VAR
+
+ ADD_TIME := IN1 + IN2;
+END_FUNCTION
+
+
+FUNCTION SUB : TIME
+ VAR_INPUT
+ IN1 : TIME;
+ IN2 : TIME;
+ END_VAR
+
+ SUB := IN1 - IN2;
+END_FUNCTION
+
+
+FUNCTION SUB_TIME : TIME
+ VAR_INPUT
+ IN1 : TIME;
+ IN2 : TIME;
+ END_VAR
+
+ SUB_TIME := IN1 - IN2;
+END_FUNCTION
+
+
+
+(**************)
+(* TIME + TOD *)
+(**************)
+
+FUNCTION ADD : TOD
+ VAR_INPUT
+ IN1 : TOD;
+ IN2 : TIME;
+ END_VAR
+
+ ADD := IN1 + IN2;
+END_FUNCTION
+
+
+(* The following function is not defined in the standard, but its existance makes sense. *)
+FUNCTION ADD : TOD
+ VAR_INPUT
+ IN1 : TIME;
+ IN2 : TOD;
+ END_VAR
+
+ ADD := IN1 + IN2;
+END_FUNCTION
+
+
+FUNCTION ADD_TOD_TIME : TOD
+ VAR_INPUT
+ IN1 : TOD;
+ IN2 : TIME;
+ END_VAR
+
+ ADD_TOD_TIME := IN1 + IN2;
+END_FUNCTION
+
+
+FUNCTION SUB : TOD
+ VAR_INPUT
+ IN1 : TOD;
+ IN2 : TIME;
+ END_VAR
+
+ SUB := IN1 - IN2;
+END_FUNCTION
+
+
+FUNCTION SUB_TOD_TIME : TOD
+ VAR_INPUT
+ IN1 : TOD;
+ IN2 : TIME;
+ END_VAR
+
+ SUB_TOD_TIME := IN1 - IN2;
+END_FUNCTION
+
+
+
+(*************)
+(* TIME + DT *)
+(*************)
+
+FUNCTION ADD : DT
+ VAR_INPUT
+ IN1 : DT;
+ IN2 : TIME;
+ END_VAR
+
+ ADD := IN1 + IN2;
+END_FUNCTION
+
+
+(* The following function is not defined in the standard, but its existance makes sense. *)
+FUNCTION ADD : DT
+ VAR_INPUT
+ IN1 : TIME;
+ IN2 : DT;
+ END_VAR
+
+ ADD := IN1 + IN2;
+END_FUNCTION
+
+
+FUNCTION ADD_DT_TIME : DT
+ VAR_INPUT
+ IN1 : DT;
+ IN2 : TIME;
+ END_VAR
+
+ ADD_DT_TIME := IN1 + IN2;
+END_FUNCTION
+
+
+
+(***************)
+(* DATE + DATE *)
+(***************)
+
+FUNCTION SUB : TIME
+ VAR_INPUT
+ IN1 : DATE;
+ IN2 : DATE;
+ END_VAR
+
+ SUB := IN1 - IN2;
+END_FUNCTION
+
+
+FUNCTION SUB_DATE_DATE : TIME
+ VAR_INPUT
+ IN1 : DATE;
+ IN2 : DATE;
+ END_VAR
+
+ SUB_DATE_DATE := IN1 - IN2;
+END_FUNCTION
+
+
+
+(*************)
+(* TOD + TOD *)
+(*************)
+
+FUNCTION SUB : TIME
+ VAR_INPUT
+ IN1 : TOD;
+ IN2 : TOD;
+ END_VAR
+
+ SUB := IN1 - IN2;
+END_FUNCTION
+
+
+FUNCTION SUB_TOD_TOD : TIME
+ VAR_INPUT
+ IN1 : TOD;
+ IN2 : TOD;
+ END_VAR
+
+ SUB_TOD_TOD := IN1 - IN2;
+END_FUNCTION
+
+
+
+(*************)
+(* TIME + DT *)
+(*************)
+
+FUNCTION SUB : DT
+ VAR_INPUT
+ IN1 : DT;
+ IN2 : TIME;
+ END_VAR
+
+ SUB := IN1 - IN2;
+END_FUNCTION
+
+
+FUNCTION SUB_DT_TIME : DT
+ VAR_INPUT
+ IN1 : DT;
+ IN2 : TIME;
+ END_VAR
+
+ SUB_DT_TIME := IN1 - IN2;
+END_FUNCTION
+
+
+
+(***********)
+(* DT + DT *)
+(***********)
+
+FUNCTION SUB : TIME
+ VAR_INPUT
+ IN1 : DT;
+ IN2 : DT;
+ END_VAR
+
+ SUB := IN1 - IN2;
+END_FUNCTION
+
+
+FUNCTION SUB_DT_DT : TIME
+ VAR_INPUT
+ IN1 : DT;
+ IN2 : DT;
+ END_VAR
+
+ SUB_DT_DT := IN1 - IN2;
+END_FUNCTION
+
+
+
+(******************)
+(* TIME * ANY_NUM *)
+(******************)
+
+FUNCTION MUL : TIME
+ VAR_INPUT
+ IN1 : TIME;
+ IN2 : LREAL;
+ END_VAR
+
+ MUL := IN1 * IN2;
+END_FUNCTION
+
+
+FUNCTION MULTIME : TIME
+ VAR_INPUT
+ IN1 : TIME;
+ IN2 : LREAL;
+ END_VAR
+
+ MULTIME := IN1 * IN2;
+END_FUNCTION
+
+
+FUNCTION DIV : TIME
+ VAR_INPUT
+ IN1 : TIME;
+ IN2 : LREAL;
+ END_VAR
+
+ DIV := IN1 / IN2;
+END_FUNCTION
+
+
+FUNCTION DIVTIME : TIME
+ VAR_INPUT
+ IN1 : TIME;
+ IN2 : LREAL;
+ END_VAR
+
+ DIVTIME := IN1 / IN2;
+END_FUNCTION
+
+
+
+(*************)
+(* DATE + DT *)
+(*************)
+
+FUNCTION CONCAT_DATE_TOD : DT
+ VAR_INPUT
+ IN1 : DATE;
+ IN2 : TOD;
+ END_VAR
+
+ CONCAT_DATE_TOD := IN1 + IN2;
+END_FUNCTION
+
+
+
+(*************************)
+(* Data Type Conversions *)
+(*************************)
+
+FUNCTION DT_TO_DATE : DATE
+ VAR_INPUT
+ IN1 : DT;
+ END_VAR
+
+ {DT_TO_DATE = IN1.__to_DATE();}
+END_FUNCTION
+
+
+
+FUNCTION DT_TO_TOD : TOD
+ VAR_INPUT
+ IN1 : DT;
+ END_VAR
+
+ {DT_TO_TOD = IN1.__to_TOD();}
+END_FUNCTION
+
+
diff -r 000000000000 -r fb772792efd1 lib/timer.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/timer.txt Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,280 @@
+(*
+ * (c) 2005 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ *)
+
+(*
+ * This is part of the library conatining the functions
+ * and function blocks defined in the standard.
+ *
+ * Timer Function Blocks
+ * ---------------------
+ *
+ * NOTE: The timing diagrams in the comments were taken from the
+ * IEC 61131-3 standard.
+ *)
+
+
+
+(****************************************************************
+
+ TP - pulse timing - state machine
+
+
+ +--------+ ++ ++ +--------+
+ IN | | || || | |
+ --+ +-----++-++---+ +---------
+ t0 t1 t2 t3 t4 t5
+ +----+ +----+ +----+
+ Q | | | | | |
+ --+ +---------+ +--+ +-------------
+ t0 t0+PT t2 t2+PT t4 t4+PT
+ PT +---+ + +---+
+ : / | /| / |
+ ET : / | / | / |
+ : / | / | / |
+ : / | / | / |
+ 0-+ +-----+ +--+ +---------
+ t0 t1 t2 t4 t5
+
+
+ 2 +---+ + +---+
+STATE 1 +----+ | +----| +----+ |
+ 0 --+ +-----+ +--+ +---------
+
+
+****************************************************************)
+
+FUNCTION_BLOCK TP
+ VAR_INPUT
+ IN : BOOL; (* first input parameter *)
+ PT : TIME; (* second input parameter *)
+ END_VAR
+ VAR_OUTPUT
+ Q : BOOL := FALSE; (* first output parameter *)
+ ET : TIME := T#0s; (* second output parameter *)
+ END_VAR
+
+ VAR
+ STATE : SINT := 0; (* internal state: 0-reset, 1-counting, 2-set *)
+ PREV_IN : BOOL := FALSE;
+ CURRENT_TIME, START_TIME : TIME;
+ END_VAR
+
+ {data__->CURRENT_TIME = __CURRENT_TIME;}
+
+ IF ((STATE = 0) AND NOT(PREV_IN) AND IN) (* found rising edge on IN *)
+ THEN
+ (* start timer... *)
+ STATE := 1;
+ Q := TRUE;
+ START_TIME := CURRENT_TIME;
+
+ ELSIF (STATE = 1)
+ THEN
+ IF ((START_TIME + PT) <= CURRENT_TIME)
+ THEN
+ STATE := 2;
+ Q := FALSE;
+ ET := PT;
+ ELSE
+ ET := CURRENT_TIME - START_TIME;
+ END_IF;
+ END_IF;
+
+ IF ((STATE = 2) AND NOT(IN))
+ THEN
+ ET := T#0s;
+ STATE := 0;
+ END_IF;
+
+
+ PREV_IN := IN;
+
+END_FUNCTION_BLOCK
+
+
+
+
+(****************************************************************
+
+ TON - On-delay timing - state machine
+
+
+ +--------+ +---+ +--------+
+ IN | | | | | |
+ --+ +--------+ +---+ +-------------
+ t0 t1 t2 t3 t4 t5
+ +---+ +---+
+ Q | | | |
+ -------+ +---------------------+ +-------------
+ t0+PT t1 t4+PT t5
+ PT +---+ +---+
+ : / | + / |
+ ET : / | /| / |
+ : / | / | / |
+ : / | / | / |
+ 0-+ +--------+ +---+ +-------------
+ t0 t1 t2 t3 t4 t5
+
+
+ 2 +---+ +---+
+STATE 1 +----+ | +---+ +----+ |
+ 0 --+ +--------+ +---+ +------
+
+
+****************************************************************)
+
+
+FUNCTION_BLOCK TON
+ VAR_INPUT
+ IN : BOOL; (* first input parameter *)
+ PT : TIME; (* second input parameter *)
+ END_VAR
+ VAR_OUTPUT
+ Q : BOOL := FALSE; (* first output parameter *)
+ ET : TIME := T#0s; (* second output parameter *)
+ END_VAR
+
+ VAR
+ STATE : SINT := 0; (* internal state: 0-reset, 1-counting, 2-set *)
+ PREV_IN : BOOL := FALSE;
+ CURRENT_TIME, START_TIME : TIME;
+ END_VAR
+
+ {data__->CURRENT_TIME = __CURRENT_TIME;}
+
+ IF ((STATE = 0) AND NOT(PREV_IN) AND IN) (* found rising edge on IN *)
+ THEN
+ (* start timer... *)
+ STATE := 1;
+ Q := FALSE;
+ START_TIME := CURRENT_TIME;
+
+ ELSE
+ (* STATE is 1 or 2 !! *)
+ IF (NOT(IN))
+ THEN
+ ET := T#0s;
+ Q := FALSE;
+ STATE := 0;
+
+ ELSIF (STATE = 1)
+ THEN
+ IF ((START_TIME + PT) <= CURRENT_TIME)
+ THEN
+ STATE := 2;
+ Q := TRUE;
+ ET := PT;
+ ELSE
+ ET := CURRENT_TIME - START_TIME;
+ END_IF;
+ END_IF;
+
+ END_IF;
+
+ PREV_IN := IN;
+
+END_FUNCTION_BLOCK
+
+
+
+
+
+(****************************************************************
+
+ TOFF - Off-delay timing - state machine
+
+
+ +--------+ +---+ +--------+
+ IN | | | | | |
+ ---+ +--------+ +---+ +-----------
+ t0 t1 t2 t3 t4 t5
+ +-------------+ +---------------------+
+ Q | | | |
+ ---+ +---+ +------
+ t0 t1+PT t2 t5+PT
+ PT +---+ +------
+ : / | + /
+ ET : / | /| /
+ : / | / | /
+ : / | / | /
+ 0------------+ +---+ +--------+
+ t1 t3 t5
+
+
+ 2 +---+ +------
+STATE 1 +----+ | +---+ +----+
+ 0 -------------+ +---+ +--------+
+
+
+****************************************************************)
+
+FUNCTION_BLOCK TOFF
+ VAR_INPUT
+ IN : BOOL; (* first input parameter *)
+ PT : TIME; (* second input parameter *)
+ END_VAR
+ VAR_OUTPUT
+ Q : BOOL := FALSE; (* first output parameter *)
+ ET : TIME := T#0s; (* second output parameter *)
+ END_VAR
+
+ VAR
+ STATE : SINT := 0; (* internal state: 0-reset, 1-counting, 2-set *)
+ PREV_IN : BOOL := FALSE;
+ CURRENT_TIME, START_TIME : TIME;
+ END_VAR
+
+ {data__->CURRENT_TIME = __CURRENT_TIME;}
+
+ IF ((STATE = 0) AND PREV_IN AND NOT(IN)) (* found falling edge on IN *)
+ THEN
+ (* start timer... *)
+ STATE := 1;
+ START_TIME := CURRENT_TIME;
+
+ ELSE
+ (* STATE is 1 or 2 !! *)
+ IF (IN)
+ THEN
+ ET := T#0s;
+ STATE := 0;
+
+ ELSIF (STATE = 1)
+ THEN
+ IF ((START_TIME + PT) <= CURRENT_TIME)
+ THEN
+ STATE := 2;
+ ET := PT;
+ ELSE
+ ET := CURRENT_TIME - START_TIME;
+ END_IF;
+ END_IF;
+
+ END_IF;
+
+ Q := IN OR (STATE = 1);
+ PREV_IN := IN;
+
+END_FUNCTION_BLOCK
+
diff -r 000000000000 -r fb772792efd1 main.cc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cc Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,133 @@
+/*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+/*
+ ****************************************************************
+ ****************************************************************
+ ****************************************************************
+ ********* *********
+ ********* *********
+ ********* O V E R A L L A R C H I T E C T U R E *********
+ ********* *********
+ ********* *********
+ ****************************************************************
+ ****************************************************************
+ ****************************************************************
+
+ The compiler works in 4(+1) stages:
+ Stage 1 - Lexical analyser - implemented with flex (iec.flex)
+ Stage 2 - Syntax parser - implemented with bison (iec.y)
+ Stage 3 - Semantics analyser - not yet implemented
+ Stage 4 - Code generator - implemented in C++
+ Stage 4+1 - Binary code generator - gcc, javac, etc...
+
+
+ Data structures passed between stages, in global variables:
+ 1->2 : tokens (int), and token values (char *)
+ 2->1 : symbol tables (defined in symtable.hh)
+ 2->3 : abstract syntax tree (tree of C++ classes, in absyntax.hh file)
+ 3->4 : Same as 2->3
+ 4->4+1 : file with program in c, java, etc...
+
+
+ The compiler works in several passes:
+ Pass 1: executes stages 1 and 2 simultaneously
+ Pass 2: executes stage 3
+ Pass 3: executes stage 4
+ Pass 4: executes stage 4+1
+*/
+
+
+
+//#include // printf()
+
+#include // EXIT_FAILURE
+#include "absyntax/absyntax.hh" // symbol_c type
+
+
+
+
+/* A macro for printing out internal parser errors... */
+#include // required for std::cerr
+#define ERROR error_exit(__FILE__,__LINE__)
+void error_exit(const char *file_name, int line_no) {
+ std::cerr << "\nInternal program error in file " << file_name
+ << " at line " << line_no << "\n\n\n";
+ exit(EXIT_FAILURE);
+}
+
+
+
+/* forward declarations... */
+int stage1_2(const char *filename, const char *includedir, symbol_c **tree_root);
+//int stage3(symbol_c *tree_root);
+int stage4(symbol_c *tree_root);
+
+
+static void printusage(const char *cmd) {
+ printf("%s [] [-I ]\n", cmd);
+}
+
+
+
+int main(int argc, char **argv) {
+ symbol_c *tree_root;
+ char * includedir = NULL;
+
+ if (argc == 4) {
+ if (strcmp(argv[2], "-I") != 0) {
+ printusage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ includedir = argv[3];
+ argc = 2;
+ }
+
+ if (argc != 2) {
+ printusage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ /* 1st Pass */
+ if (stage1_2(argv[1], includedir, &tree_root) < 0)
+ return EXIT_FAILURE;
+
+ /* 2nd Pass */
+ /* not yet implemented... */
+ /*
+ if (stage3(tree_root) < 0)
+ return EXIT_FAILURE;
+ */
+
+ /* 3rd Pass */
+ if (stage4(tree_root) < 0)
+ return EXIT_FAILURE;
+
+ /* 4th Pass */
+ /* Currently implemented in the Makefile! */
+
+ return 0;
+}
+
+
diff -r 000000000000 -r fb772792efd1 readme
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/readme Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,407 @@
+
+
+
+ IEC 61131-3 IL and ST compiler
+
+
+ The following compiler has been based on the
+ FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+
+
+ (c) 2003 Mario de Sousa
+
+
+
+****************************************************************
+****************************************************************
+****************************************************************
+********* *********
+********* *********
+********* O V E R A L L A R C H I T E C T U R E *********
+********* *********
+********* *********
+****************************************************************
+****************************************************************
+****************************************************************
+
+ The compiler works in 4(+1) stages:
+ Stage 1 - Lexical analyser - implemented with flex (iec.flex)
+ Stage 2 - Syntax parser - implemented with bison (iec.y)
+ Stage 3 - Semantics analyser - not yet implemented
+ Stage 4 - Code generator - implemented in C++
+ Stage 4+1 - Binary code generator - gcc, javac, etc...
+
+
+ Data structures passed between stages, in global variables:
+ 1->2 : tokens (int), and token values (char *)
+ 2->1 : symbol tables (defined in symtable.hh)
+ 2->3 : abstract syntax tree (tree of C++ classes, in absyntax.hh file)
+ 3->4 : Same as 2->3
+ 4->4+1 : file with program in c, java, etc...
+
+
+ The compiler works in several passes:
+ Pass 1: executes stages 1 and 2 simultaneously
+ Pass 2: executes stage 3
+ Pass 3: executes stage 4
+ Pass 4: executes stage 4+1
+
+
+ NOTE 1
+ ======
+ Note that stage 2 passes data back to stage 1. This is only
+possible because both stages are executed in the same pass.
+
+
+
+ NOTE 2
+ ======
+ I (Mario) have a feeling that the abstract syntax may be
+considerably simplified without any drawbacks to semantic checking
+and code generation. I have nevertheless opted to keep as much
+info as possible in the abstract syntax tree, in case it may become
+necessary further on.
+ Once we start coding the next stages (semantic checking and code
+generation) I will get a better understanding of what is required
+of the abstract syntax tree. At that stage I will be better
+positioned to make a more informed decision on how best to structure
+the abstract syntax tree.
+ For now, we play conservative and keep as much info as possible.
+
+
+
+ NOTE 3
+ ======
+ It would be nice to get this parser integrated into the gcc
+group of compilers. We would then be able to compile our st/il
+programs directly into executable binaries, for all the processor
+architectures gcc currently supports.
+ The gcc compilers are divided into a frontend and backend. The
+data structure between these two stages is called the syntax
+tree. In essence, we would need to create a new frontend that
+would parse the st/il program and build the syntax tree.
+Unfortunately the gcc syntax tree is not very well documented,
+and doing semantic checking on this tree would probably be a
+nightmare.
+ We therefore chose to follow the same route as the gnat (ada 95)
+and cobol compilers, i.e. generate our own abstract syntax tree,
+do semantic checking on our tree, do whatever optimisation
+we can at this level on our own tree, and only then build
+the gcc syntax tree from our abstract syntax tree.
+ All this may still be integrated with the gcc backend to generate
+a new gnu compiler for the st and il programming languages.
+Since generating the gcc syntax tree will probably envolve some
+trial and error effort due to the sparseness of documentation,
+we chose to start off by coding a C++ code generator for
+our stage 4. We may later implement a gcc syntax tree generator
+as an alternative stage 4 process, and then integrate it with
+the gcc toplevel.c file (command line parsing, etc...).
+
+
+
+****************************************************************
+****************************************************************
+****************************************************************
+********* *********
+********* *********
+********* S T A G E 1 *********
+********* *********
+********* *********
+****************************************************************
+****************************************************************
+****************************************************************
+
+
+
+Issue 1
+=======
+
+ The syntax defines the common_character_representation as:
+ |
+
+ 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 (Note how
+common_character_representation could be defined by
+subtracting '$' '"' and "'" from print_char() ).
+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...
+
+ In short, the definition we use for common_character_representation
+only works for ASCII character encoding!
+
+
+
+
+Issue 2
+=======
+
+We extend the IEC 61131-3 standard syntax to allow inclusion of
+other files. The accepted syntax is:
+
+ (*#include "" *)
+
+Note how this would be ignored by other standard complient compilers
+as a simple comment!
+
+
+
+****************************************************************
+****************************************************************
+****************************************************************
+********* *********
+********* *********
+********* S T A G E 2 *********
+********* *********
+********* *********
+****************************************************************
+****************************************************************
+****************************************************************
+
+ Overall Comments
+ ================
+
+
+ Comment 1
+ ---------
+ We have augmented the syntax the specification defines to include
+restrictions defined in the semantics of the languages.
+
+ This is required because the syntax cannot be parsed by a LALR(1)
+parser as it is presented in the specification. Many reduce/reduce
+and shift/reduce conflicts arise. This is mainly because the parser
+cannot discern how to reduce an identifier. Identifiers show up in
+many places in the syntax, and it is not entirely possible to
+figure out if the identifier is a variable_name, enumeration
+value, function block name, etc... only from the context in
+which it appears.
+
+ A more detailed example of why we need symbol tables are
+the type definitions... In definition of new types
+(section B 1.3.3) the parser needs to figure out the class of
+the new type being defined (enumerated, structure, array, etc...).
+This works well when the base classes are elementary types
+(or structures, enumeration, arrays, etc. thereof). It becomes
+confusing to the parser when the new_type is based on a previously
+user defined type.
+
+TYPE
+ new_type_1 : INT := 99;
+ new_type_2 : new_type_1 := 100;
+END_TYPE
+
+ When parsing new_type_1, the parser can figure out that the
+identifier new_type_1 is a simple_type_name, because it is
+based on a elementary type without structure, arrays, etc...
+ While parsing new_type_2, it becomes confused how to reduce
+the new_type_2 identifier, as it is based on the identifier
+new_type_1, of which it does not know the class (remember, at this
+stage new_type_1 is a simple identifier!).
+ We therefore need to keep track of the class of the user
+defined types as they are declared, so that the lexical analyser
+can tell the syntax parser what class the type belongs to. We
+cannot use the abstract syntax tree itself to search for the
+declaration of new_type_1 as we only get a handle to the root
+of the tree at the end of the parsing.
+
+ We therefore maintain an independent and parallel table of symbols,
+that is filled as we come across the type delcarations in the code.
+Actually, we ended up also needing to store variable names in
+the symbol table. Since variable names come and go out of scope
+depending on what portion of code we are parsing, we sometimes
+need to remove the variable names from the symbol table.
+Since the ST and IL languages only have a single level of scope,
+I (Mario) found it easier to simply use a second symbol table for
+the variable names that is completely cleared when the parser
+reaches the end of a function (function block or program).
+
+What I mean when I say that these languages have a single level
+of scope is that all variables used in a function (function block
+or program) must be declared inside that function (function block
+or program). Even global variables must be re-declared as EXTERN
+before a function may access them! This means that it is easy
+to simply load up the variable name symbol table when we start
+parsing a function (function block or program), and to clear it
+when we reach the end. Checking whether variables declared
+as EXTERN really exist inside a RESOURCE or a CONFIGURATION
+is left to stage 3 (semantic checking) where we can use the
+abstract tree itself to search for the variables (NOTE: semantic
+cheching at stage 3 has not yet been implemented, so we may yet
+end up using a symbol table too at that stage!).
+
+ Due to the use of the symbol tables, and special identifier
+tokens depending on the type of identifier it had previously
+been declared in the code being parsed, the syntax was slightly
+changed regarding the definition of variable names, derived
+function names, etc... FROM for e.g.:
+variable_name: identifier;
+TO
+variable_name: variable_name_token;
+
+ Flex first looks at the symbol tables when it finds an identifier,
+and returns the correct token corresponding to the identifier
+type in question. Only if the identifier is not currently stored
+in any symbol table, does flex return a simple identifier_token.
+
+ This means that the declarations of variables, functions etc...
+were changed FROM:
+function_declaration: FUNCTION derived_function_name ...
+TO
+function_declaration: FUNCTION identifier ...
+since the initial definition of derived_function_name had been
+changed FROM
+derived_function_name: identifier;
+TO
+derived_function_name: derived_function_name_token;
+
+
+
+
+ Comment 2
+ ---------
+ Since the ST and IL languages share a lot of common syntax,
+I have decided to write a single parser to handle both languages
+simultaneously. This approach has the advantage that the user
+may mix the language used in the same file, as long as each function
+is written in a single lanuage.
+
+ This approach also assumes that all the IL language operators are
+keywords, which means that it is not possible to define variables
+using names such as "LD", "ST", etc...
+Note that the spec does not consider these operators to be keywords,
+so it means that they should be available for variable names! On the
+other hand, all implementations of the ST and IL languages seems to
+treat them as keywords, so there is not much harm in doing the same.
+
+ If it ever becomes necessary to allow variables with names of IL
+operators, either the syntax will have to be augmented, or we can
+brake up the parser in two: one for ST and another for IL.
+
+
+
+/********************************/
+/* B 1.3.3 - Derived data types */
+/********************************/
+
+Issue 1
+=======
+
+According to the spec, the valid construct
+TYPE new_str_type : STRING := "hello!"; END_TYPE
+has two possible routes to type_declaration...
+
+Route 1:
+type_declaration: single_element_type_declaration
+single_element_type_declaration: simple_type_declaration
+simple_type_declaration: identifier ':' simple_spec_init
+simple_spec_init: simple_specification ASSIGN constant
+(shift: identifier <- 'new_str_type')
+simple_specification: elementary_type_name
+elementary_type_name: STRING
+(shift: elementary_type_name <- STRING)
+(reduce: simple_specification <- elementary_type_name)
+(shift: constant <- "hello!")
+(reduce: simple_spec_init: simple_specification ASSIGN constant)
+(reduce: ...)
+
+
+Route 2:
+type_declaration: string_type_declaration
+string_type_declaration: identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init
+(shift: identifier <- 'new_str_type')
+elementary_string_type_name: STRING
+(shift: elementary_string_type_name <- STRING)
+(shift: string_type_declaration_size <- /* empty */)
+string_type_declaration_init: ASSIGN character_string
+(shift: character_string <- "hello!")
+(reduce: string_type_declaration_init <- ASSIGN character_string)
+(reduce: string_type_declaration <- identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init )
+(reduce: type_declaration <- string_type_declaration)
+
+
+ At first glance it seems that removing route 1 would make
+the most sense. Unfortunately the construct 'simple_spec_init'
+shows up multiple times in other rules, so changing this construct
+would mean changing all the rules in which it appears.
+I (Mario) therefore chose to remove route 2 instead. This means
+that the above declaration gets stored in a
+simple_type_declaration_c, and not in a string_type_declaration_c
+as would be expected!
+
+
+/***********************/
+/* B 1.5.1 - Functions */
+/***********************/
+
+
+Issue 1
+=======
+
+ 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
+variable_name_token.
+
+ BUT, in functions the function name may be used as
+a variable! In order to be able to parse this correctly,
+the token parser (flex) must return a 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 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 the extra
+construct 'function_name_declaration', i.e. to force
+the parser to reduce it, before parsing the function body,
+and therefore get an oportunity to insert the function name
+into the variable name symbol table!
+
+
+/********************************/
+/* B 3.2.4 Iteration Statements */
+/********************************/
+
+Issue 1
+=======
+
+For the 'FOR' iteration loop
+
+ FOR control_variable ASSIGN expression TO expression BY expression DO statement_list END_FOR
+
+The spec declares the control variable in the syntax as
+
+ 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 .. VAR_END' construct, so I (Mario) changed
+the syntax to read
+
+ control_variable: variable_name;
+
+
+
+
+
+**************************************************************************
+
+ (c) 2003 Mario de Sousa
diff -r 000000000000 -r fb772792efd1 stage1_2/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/stage1_2/Makefile Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,49 @@
+# include the system specific Makefile
+#include ../../../Makefile.$(shell uname)
+
+
+
+default: all
+
+.PHONY: iec.flex
+
+all: iec.flex.o iec.y.o
+
+clean:
+ -rm -f *.o Makefile.depend
+ -rm -f iec.flex.c iec.y.cc iec.y.hh iec.y.output
+ -rm -f test_flex
+
+#get warnings, debugging information and optimization
+CFLAGS = -Wall -pedantic -Wpointer-arith -Wwrite-strings
+# CFLAGS += -Werror
+
+CFLAGS += -ggdb -O3 -funroll-loops
+# Note: if the optimizer crashes, we'll leave out the -O3 for those files
+
+CFLAGS += -I. -I../* -I../../absyntax
+
+test_flex: iec.flex.c iec.y.hh
+ $(CXX) -o test_flex.o -c iec.flex.c -DTEST_MAIN $(CFLAGS)
+ $(CXX) -o test_flex test_flex.o
+# $(CXX) -o test_flex test_flex.o ../util/symtable.o -DTEST_MAIN
+
+iec.flex.c: iec.flex
+ flex -oiec.flex.c iec.flex
+
+iec.flex.o: iec.y.hh iec.flex.c
+ $(CXX) -c iec.flex.c -D LIBDIRECTORY='"$(IECLIBDIR)"' $(CFLAGS)
+
+iec.y.hh iec.y.cc: iec.y
+ bison -d -v -o iec.y.cc iec.y
+
+iec.y.o: iec.y.cc iec.y.hh
+ $(CXX) -c iec.y.cc -D LIBDIRECTORY='"$(IECLIBDIR)"' $(CFLAGS)
+
+
+
+
+
+#how to make things from other directories if they are missing
+../% /%:
+ $(MAKE) -C $(@D) $(@F)
diff -r 000000000000 -r fb772792efd1 stage1_2/iec.flex
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/stage1_2/iec.flex Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,1384 @@
+/*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST 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
+
+/**************************************************/
+/* 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 LIBDIRECTORY "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"
+
+/* 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...
+ */
+extern const char *current_filename;
+
+/* We will not be using unput() in our flex code... */
+#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;
+
+/* 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 = yylloc.last_line = yylineno; \
+ yylloc.first_column = yylloc.last_column = 0; \
+ }
+
+
+/* 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 delcare 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 or il) 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.
+ * The body state returns any matched text back to the buffer with unput(),
+ * to be later matched correctly by the apropriate language parser (st or il).
+ * The state machine has 6 possible states (INITIAL, config, decl, body, st, il)
+ * Possible state changes are:
+ * INITIAL -> decl (when a FUNCTION, FUNCTION_BLOCK, or PROGRAM is found,
+ * and followed by a VAR declaration)
+ * INITIAL -> body (when a FUNCTION, FUNCTION_BLOCK, or PROGRAM is found,
+ * and _not_ followed by a VAR declaration)
+ * INITIAL -> config (when a CONFIGURATION is found)
+ * decl -> body (when the last END_VAR is found, i.e. the function body starts)
+ * body -> st (when it figures out it is parsing st language)
+ * body -> il (when it figures out it is parsing il language)
+ * decl -> INITIAL (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found)
+ * st -> INITIAL (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found)
+ * il -> INITIAL (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found)
+ * config -> INITIAL (when a END_CONFIGURATION is found)
+ */
+/* we are parsing a configuration. */
+%s config
+
+/* we are parsing a function, program or function block declaration */
+%s decl
+
+/* we will be parsing a function body. Whether il/st is remains unknown */
+%x body
+
+/* we are parsing il code -> flex must return the EOL tokens! */
+%s il
+
+/* we are parsing st code -> flex must not return the EOL tokens! */
+%s st
+
+
+
+
+/*******************/
+/* 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;
+ int lineno;
+ const char *filename;
+ } include_stack_t;
+
+include_stack_t include_stack[MAX_INCLUDE_DEPTH];
+int include_stack_ptr = 0;
+
+const char *INCLUDE_DIRECTORIES[] = {
+ "",
+ "lib/",
+ "/lib/",
+ "/usr/lib/",
+ "/usr/lib/iec/",
+ LIBDIRECTORY "/",
+ NULL /* must end with NULL!! */
+ };
+
+
+/*
+ * Join two strings together. Allocate space with malloc(3).
+ */
+static char *strdup2(const char *a, const char *b) {
+ char *res = (char *)malloc(strlen(a) + strlen(b) + 1);
+
+ if (!res)
+ return NULL;
+ return strcat(strcpy(res, a), b); /* safe, actually */
+}
+%}
+
+
+
+/*****************************/
+/* Prelimenary constructs... */
+/*****************************/
+
+
+/* A 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 %{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. For the other names, this would create havoc!!!
+ */
+direct_variable %{identifier}
+
+/******************************************/
+/* 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 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);
+
+ /* 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)-2] = '\0';
+ yylval.ID=strdup(yytext+1);
+ return pragma_token;
+ }
+{pragma} {/* return the pragmma without the enclosing '{' and '}' */
+ yytext[strlen(yytext)-2] = '\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]).lineno = yylineno;
+ (include_stack[include_stack_ptr]).filename = current_filename;
+ include_stack_ptr++;
+ yylineno = 1;
+ current_filename = strdup(yytext);
+
+ for (i = 0, yyin = NULL; (INCLUDE_DIRECTORIES[i] != NULL) && (yyin == NULL); i++) {
+ char *full_name = strdup2(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 );
+ }
+
+ /* 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... */
+ }
+
+
+<> {
+ if (--include_stack_ptr < 0) {
+ yyterminate();
+ } else {
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer((include_stack[include_stack_ptr]).buffer_state);
+ yylineno = include_stack[include_stack_ptr].lineno;
+ /* 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 opne that gets stored in include_stack[0],
+ * which is never free'd!
+ */
+ 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 */
+{
+ /* NOTE: how about functions that do not delcare variables, and go directly to the body???
+ * - 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.
+ * 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); return FUNCTION;
+FUNCTION_BLOCK BEGIN(decl); return FUNCTION_BLOCK;
+PROGRAM BEGIN(decl); return PROGRAM;
+CONFIGURATION BEGIN(config); return CONFIGURATION;
+}
+
+ /* INITIAL -> body */
+ /* required if the function, program, etc.. has no VAR block! */
+{
+FUNCTION BEGIN(body); return FUNCTION;
+FUNCTION_BLOCK BEGIN(body); return FUNCTION_BLOCK;
+PROGRAM BEGIN(body); return PROGRAM;
+}
+
+ /* decl -> body */
+{
+END_VAR{st_whitespace}VAR unput_text(strlen("END_VAR")); return END_VAR;
+END_VAR{st_whitespace} unput_text(strlen("END_VAR")); BEGIN(body); return END_VAR;
+}
+
+ /* body -> (il | st) */
+{
+{qualified_identifier}{st_whitespace}":=" unput_text(0); BEGIN(st);
+{qualified_identifier}"[" unput_text(0); BEGIN(st);
+
+RETURN unput_text(0); BEGIN(st);
+IF unput_text(0); BEGIN(st);
+CASE unput_text(0); BEGIN(st);
+FOR unput_text(0); BEGIN(st);
+WHILE unput_text(0); BEGIN(st);
+REPEAT unput_text(0); BEGIN(st);
+EXIT unput_text(0); BEGIN(st);
+
+
+{identifier} {int token = get_identifier_token(yytext);
+ if (token == prev_declared_fb_name_token) {
+ /* the code has a call to a function block */
+ BEGIN(st);
+ } else {
+ BEGIN(il);
+ }
+ unput_text(0);
+ }
+. unput_text(0); BEGIN(il);
+
+} /* end of body lexical parser */
+
+ /* (decl | body | il | st) -> 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,
+ *
+ * TODO: how about function names?
+ */
+{identifier} {int token = get_identifier_token(yytext);
+ if ((token == prev_declared_variable_name_token) ||
+ (token == prev_declared_fb_name_token)) {
+ /*
+ if (token != identifier_token)
+ */
+ /* NOTE: if we use the above line, then 'MOD' et al must be removed
+ * from the library_symbol_table as a default function name!
+ */
+ yylval.ID=strdup(yytext);
+ return token;
+ }
+ /* otherwise, leave it for the other lexical parser rules... */
+ REJECT;
+ }
+
+
+ /******************************************************/
+ /******************************************************/
+ /******************************************************/
+ /***** *****/
+ /***** *****/
+ /***** N O W D O T H E K E Y W O R D S *****/
+ /***** *****/
+ /***** *****/
+ /******************************************************/
+ /******************************************************/
+ /******************************************************/
+
+
+EN return EN;
+ENO return ENO;
+
+
+ /******************************/
+ /* B 1.2.1 - Numeric Literals */
+ /******************************/
+TRUE return TRUE;
+BOOL#1 return TRUE;
+FALSE return FALSE;
+BOOL#0 return FALSE;
+
+
+ /************************/
+ /* B 1.2.3.1 - Duration */
+ /************************/
+t# return T_SHARP;
+T# return T_SHARP;
+TIME return TIME;
+
+
+ /************************************/
+ /* B 1.2.3.2 - Time of day and Date */
+ /************************************/
+TIME_OF_DAY return TIME_OF_DAY;
+TOD return TIME_OF_DAY;
+DATE return DATE;
+d# return D_SHARP;
+D# return D_SHARP;
+DATE_AND_TIME return DATE_AND_TIME;
+DT return DATE_AND_TIME;
+
+
+ /***********************************/
+ /* B 1.3.1 - Elementary Data Types */
+ /***********************************/
+BYTE return BYTE;
+WORD return WORD;
+DWORD return DWORD;
+LWORD return LWORD;
+
+
+ /********************************/
+ /* 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;
+ANY_DERIVED return ANY_DERIVED;
+ANY_ELEMENTARY return ANY_ELEMENTARY;
+ANY_MAGNITUDE return ANY_MAGNITUDE;
+ANY_NUM return ANY_NUM;
+ANY_REAL return ANY_REAL;
+ANY_INT return ANY_INT;
+ANY_BIT return ANY_BIT;
+ANY_STRING return ANY_STRING;
+ANY_DATE return ANY_DATE;
+
+
+ /********************************/
+ /* B 1.3.3 - Derived data types */
+ /********************************/
+":=" return ASSIGN;
+".." return DOTDOT;
+TYPE return TYPE;
+END_TYPE return END_TYPE;
+ARRAY return ARRAY;
+OF return OF;
+STRUCT return STRUCT;
+END_STRUCT return END_STRUCT;
+
+
+ /*********************/
+ /* B 1.4 - Variables */
+ /*********************/
+REAL return REAL;
+LREAL return LREAL;
+
+SINT return SINT;
+INT return INT;
+DINT return DINT;
+LINT return LINT;
+
+USINT return USINT;
+UINT return UINT;
+UDINT return UDINT;
+ULINT return ULINT;
+
+
+WSTRING return WSTRING;
+STRING return STRING;
+BOOL return BOOL;
+
+TIME return TIME;
+DATE return DATE;
+DT return DT;
+TOD return TOD;
+DATE_AND_TIME return DATE_AND_TIME;
+TIME_OF_DAY return TIME_OF_DAY;
+
+
+ /******************************************/
+ /* B 1.4.3 - Declaration & Initialisation */
+ /******************************************/
+VAR_INPUT return VAR_INPUT;
+VAR_OUTPUT return VAR_OUTPUT;
+VAR_IN_OUT return VAR_IN_OUT;
+VAR_EXTERNAL return VAR_EXTERNAL;
+VAR_GLOBAL return VAR_GLOBAL;
+END_VAR return END_VAR;
+RETAIN return RETAIN;
+NON_RETAIN return NON_RETAIN;
+R_EDGE return R_EDGE;
+F_EDGE return F_EDGE;
+AT return AT;
+
+
+ /***********************/
+ /* B 1.5.1 - Functions */
+ /***********************/
+FUNCTION return FUNCTION;
+END_FUNCTION return END_FUNCTION;
+VAR return VAR;
+CONSTANT return CONSTANT;
+
+
+ /*****************************/
+ /* B 1.5.2 - Function Blocks */
+ /*****************************/
+FUNCTION_BLOCK return FUNCTION_BLOCK;
+END_FUNCTION_BLOCK return END_FUNCTION_BLOCK;
+VAR_TEMP return VAR_TEMP;
+VAR return VAR;
+NON_RETAIN return NON_RETAIN;
+END_VAR return END_VAR;
+
+
+ /**********************/
+ /* B 1.5.3 - Programs */
+ /**********************/
+PROGRAM return PROGRAM;
+END_PROGRAM return END_PROGRAM;
+
+
+ /********************************************/
+ /* 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;
+END_ACTION return END_ACTION;
+
+TRANSITION return TRANSITION;
+END_TRANSITION return END_TRANSITION;
+FROM return FROM;
+TO return TO;
+PRIORITY return PRIORITY;
+
+INITIAL_STEP return INITIAL_STEP;
+STEP return STEP;
+END_STEP return END_STEP;
+
+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;
+END_CONFIGURATION return END_CONFIGURATION;
+TASK return TASK;
+RESOURCE return RESOURCE;
+ON return ON;
+END_RESOURCE return END_RESOURCE;
+VAR_CONFIG return VAR_CONFIG;
+VAR_ACCESS return VAR_ACCESS;
+END_VAR return END_VAR;
+WITH return WITH;
+PROGRAM return PROGRAM;
+RETAIN return RETAIN;
+NON_RETAIN return NON_RETAIN;
+PRIORITY return PRIORITY;
+SINGLE return SINGLE;
+INTERVAL return INTERVAL;
+READ_WRITE return READ_WRITE;
+READ_ONLY return READ_ONLY;
+
+
+ /***********************************/
+ /* 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)!
+ */
+LD return LD;
+LDN return LDN;
+ST return ST;
+STN return STN;
+NOT return NOT;
+S return S;
+R return R;
+S1 return S1;
+R1 return R1;
+CLK return CLK;
+CU return CU;
+CD return CD;
+PV return PV;
+IN return IN;
+PT return PT;
+AND return AND;
+& return AND2;
+OR return OR;
+XOR return XOR;
+ANDN return ANDN;
+&N return ANDN2;
+ORN return ORN;
+XORN return XORN;
+ADD return ADD;
+SUB return SUB;
+MUL return MUL;
+DIV return DIV;
+MOD return MOD;
+GT return GT;
+GE return GE;
+EQ return EQ;
+LT return LT;
+LE return LE;
+NE return NE;
+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;
+"<>" return OPER_NE;
+">=" return OPER_GE;
+"<=" return OPER_LE;
+AND return AND;
+XOR return XOR;
+OR return OR;
+NOT return NOT;
+MOD return MOD;
+
+
+ /*****************************************/
+ /* B 3.2.2 Subprogram Control Statements */
+ /*****************************************/
+:= return ASSIGN;
+=> return SENDTO;
+RETURN return RETURN;
+
+
+ /********************************/
+ /* B 3.2.3 Selection Statements */
+ /********************************/
+IF return IF;
+THEN return THEN;
+ELSIF return ELSIF;
+ELSE return ELSE;
+END_IF return END_IF;
+
+CASE return CASE;
+OF return OF;
+ELSE return ELSE;
+END_CASE return END_CASE;
+
+
+ /********************************/
+ /* B 3.2.4 Iteration Statements */
+ /********************************/
+FOR return FOR;
+TO return TO;
+BY return BY;
+DO return DO;
+END_FOR return END_FOR;
+
+WHILE return WHILE;
+DO return DO;
+END_WHILE return END_WHILE;
+
+REPEAT return REPEAT;
+UNTIL return UNTIL;
+END_REPEAT return END_REPEAT;
+
+EXIT return EXIT;
+
+
+
+
+
+ /********************************************************/
+ /********************************************************/
+ /********************************************************/
+ /***** *****/
+ /***** *****/
+ /***** 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 direct_variable_token;}
+
+
+ /******************************************/
+ /* 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].lineno);
+}
+
+
+/* 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')
+ yylineno--;
+
+ /* 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 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 000000000000 -r fb772792efd1 stage1_2/iec.y
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/stage1_2/iec.y Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,5422 @@
+/*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST 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. 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"
+
+/* file with the declarations of symbol tables... */
+#include "../util/symtable.hh"
+
+
+/* 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; \
+ } \
+}
+
+
+/* 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);
+
+
+/*********************************/
+/* The global symbol tables... */
+/*********************************/
+/* NOTE: declared static because they are not accessed
+ * directly by the lexical parser (flex), but rather
+ * through the function get_identifier_token()
+ */
+/* A symbol table to store all the library elements */
+/* e.g.:
+ *
+ *
+ *
+ *
+ */
+static symtable_c library_element_symtable;
+
+/* A symbol table to store the declared variables of
+ * the function currently being parsed...
+ */
+static symtable_c variable_name_symtable;
+
+
+/*************************/
+/* global variables... */
+/*************************/
+static symbol_c *tree_root = NULL;
+
+/* The name of the file currently being parsed...
+ * Note that flex accesses and updates this global variable
+ * apropriately whenever it comes across an (*#include *)
+ * directive...
+ */
+const char *current_filename = NULL;
+
+/* 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...
+ */
+bool allow_function_overloading = false;
+
+
+/************************/
+/* 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);
+
+/* print an error message */
+void print_err_msg(const char *filename, int lineno, const char *additional_error_msg);
+
+
+/************************/
+/* forward declarations */
+/************************/
+/* The functions declared here are defined in iec.flex... */
+void print_include_stack(void);
+
+
+%}
+
+
+
+%union {
+ symbol_c *leaf;
+ list_c *list;
+ char *ID; /* token value */
+ struct {
+ symbol_c *first;
+ symbol_c *second;
+ } double_symbol; /* used by il_simple_operator_clash_il_operand */
+}
+
+
+
+
+
+
+/*****************************/
+/* Prelimenary constructs... */
+/*****************************/
+%type start
+
+%type any_identifier
+
+%token prev_declared_variable_name_token
+%token prev_declared_fb_name_token
+%type prev_declared_variable_name
+%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
+
+
+/* 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
+
+
+/* The pragmas... */
+%token pragma_token
+%type pragma
+
+
+/* Where do these tokens belong ?? */
+/* TODO: get the syntax parser to handle these tokens... */
+%token EN
+%token ENO
+
+
+
+/***************************/
+/* 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
+/* a helper symbol for expression */
+%type non_negative_constant
+
+
+/******************************/
+/* B 1.2.1 - Numeric Literals */
+/******************************/
+/* Done totally within flex...
+ bit
+*/
+%type numeric_literal
+/* helper symbol for non_negative_constant */
+%type non_negative_numeric_literal
+%type integer_literal
+%type signed_integer
+/* a helper symbol for non_negative_constant */
+%type non_negative_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
+/* helper symbol for non_negative_real_literal */
+%type non_negative_signed_real
+%type real_literal
+/* helper symbol for non_negative_numeric_literal */
+%type non_negative_real_literal
+// %type exponent
+%type bit_string_literal
+%type boolean_literal
+
+%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
+
+
+/********************************/
+/* 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 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
+%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 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