【实习之T100开发】Genero FGL (TIPTOP4GL) 学习笔记(1)

【实习】T100学习笔记

Genero FGL 简介

Genero FGL 语言,为 Four J’s(http://www.4js.com)于 2004 年所发表。整体结构为承袭 INFORMIX 数据库的 4GL 管理语言而来,即 INFORMIX-4GL 。

INFORMIX-4GL 属于第四代架构的语言,其优点在于构成程序的语法和英文近似,可以大幅减少学习的时间,但仅能使用于 INFORMIX 数据库的控制上。

Four J’s 取其优点,为了能够应用于更多后端数据库,开发出 FGL 语言,并因应图型化,改版为Genero FGL,有以下特点:

  • 切分为 Client、Server 架构(GDC 与 fgl),增进执行效率
  • 以 XML Bsae 做为 Client 及 Server 端数据传递的架构
  • 支援更多不同平台(OS)及数据库系统
  • 可在运行时间动态调整画面输出的格式(Layout Styles)
  • 引入基本的 对象(Object) 概念

在这里插入图片描述
在 Genero FGL 语言架构中,将 程序逻辑、画面 视为不同的项目,分别撰写。
Program(程序)= MODULE(逻辑代码) + FORM(画面代码)
在这里插入图片描述
由上图可知:

  1. Program 可由许多的 Module 与 Form 构成。
  2. 单一的 4GL 由一个或一个以上的 Function、Report 组成。
  3. 一个完整的 Program 中,必需指定一个『Main』作为程序执行入口。

Genero FGL 开发(编译、连接、执行)

当程序及画面编写完成后,还需经过编绎(Compile)连结(Link),才能够被执行(Execute)
编译需要 Genero Development License,连结及执行需要 Genero Runtime License。

编译流程
在这里插入图片描述
程序的原始文件后缀名为 .4gl,经过编译后会产生后缀为 .42m 的文件。
程序(Program)的编译fglcomp [编译参数] 待编译文件名[.4gl]

编译前处理(preprcessor) ????????

GeneroFGL 可直接以 文字编辑程序如Vim 进行 文字格式(per 档)的开发;
也可使用 Genero Studio 内的『Form Design』功能开发 XML格式(4fd 档)的画面;
编译后都会产生后缀名为 .42f 的文件。

文字格式(per文件)编译fglform [编译参数] 待编译文件名[.per]
XML 格式(4fd文件)编译gsform [编译参数] 待编译文件名[.4fd]


连结流程

若该程序不需要使用其他 4gl 提供的功能,可以略过连接的程序,直接执行作业。
若该作业被切分成许多子程序,则可在执行连接前,先将子程序打包成一组动态链接函式库(Dynamic Link Library),后缀名为 .42x,打包完成后再与原始作业进行连接。
在这里插入图片描述
连接语法:fgllink -o 连结后的完整文件名 待连结文件1 [待连结文件2] ….

示例:

  1. fgllink -o test.42x test1.42m test2.42m test3.42m(生成42x文件)
  2. fgllink -o program.42r test.42x main.42m others.42m(生成42r文件)

注:画面文件不需要执行链接


执行程序

执行程序前,需先开启使用者端的 Genero 桌面客户端软件(GDC:Genero Desktop
Client),以令主机端的 fglrun 可以与客户端的『GDC』进行沟通。
在这里插入图片描述
执行指令:fglrun [执行参数] 执行文件名[.42r]

当程序未使用到其他外部资源时,也可以直接执行含 MAIN 函数的 .42m 文件。

程序执行的过程中,所有逻辑运算均于主机端执行,只有画面异动数据会以连续的 XML 封包传递到客户端,经过 GDC 解译重组后,与使用者进行互动。

fglrun -V 可以查看 fgl 的版本号。
在这里插入图片描述

第一个程序 Hello World

MAIN
	DISPLAY "hello world!!"
END MAIN

在这里插入图片描述

4GL中的 注释

  • { } 可以将某个范围做备注
  • #-- 将某行做备注

变量与运算符

变量类型
在这里插入图片描述

变量定义(DEFINE)

直接定义变量DEFINE 变量名 变量类型
定义变量对应数据库字段DEFINE 变量名 LIKE 数据表.数据字段

# 直接定义 employee_no 变量, 类型是 CHAR(10)
DEFINE employee_no CHAR(10)

# 定义 p_employee_no 和数据库对应
DEFINE p_employee_no LIKE employee_file.employee_no,
	   p_team_no SMALLINT,
	   p_join_date, p_birthday DATE

预定义变量

Genero 的预定义变量及用途,可以直接使用。
在这里插入图片描述

变量集合(RECORD )

直接定义变量集合(Records)
例:直接定义 rec 这个 Records 中的各个变量类型。

DEFINE rec RECORD # 定义rec这个变量,它是个RECORD,是个变量集合
	id INTEGER,
	name VARCHAR(100),
	birth DATE
END RECORD

定义变量集合对应数据库字段
例:定义 cust01 这个 Record 的变量与数据库中的 customer 这个 table 的字段有相同的名称及数据类型,有以下两种方法。

DATABASE example_database

MAIN
	DEFINE cust01 RECORD LIKE customer.*
END MAIN
DATABASE example_database

MAIN
	DEFINE cust02 RECORD
		id LIKE customer.id,
		name LIKE customer.name,
		birth LIKE customer.birth,
		sales LIKE salesman.name
	END RECORD
END MAIN

数据结构(TYPE)

使用数据结构TYPE[PRIVATE|PUBLIC] TYPE 变量名 变量类型

TYPE customer RECORD
	cust_num INTEGER,
 	cust_name VARCHAR(50),
 	cust_addr VARCHAR(200)
END RECORD
DEFINE c customer

???????

PUBLIC TYPE rpt_order RECORD
	order_num INTEGER,
	store_num INTEGER,
	order_date DATE,
	fac_code CHAR(3)
END RECORD

MAIN
	DEFINE o rpt_order #使用数据结构 rpt_order 并取名为 o
	DECLARE order_c CURSOR FOR
	SELECT order_num, store_num, order_date, fac_code FROM orders
	START REPORT order_list
	FOREACH order_c INTO o.*
	OUTPUT TO REPORT order_list(o.*)
	END FOREACH
	FINISH REPORT order_list
END MAIN

变量赋值(LET)、初始化(INITIALIZE)

变量赋值LET varibale = expression

MAIN
	DEFINE c1, c2 CHAR(10)
	LET c1 = "Genero"
	LET c2 = c1
END MAIN

注:若变量形态为 CHAR 和 VARCHAR 时,指定给予的值有差异。
在这里插入图片描述


初始化变量集合(INITIALIZE)
用于初始化一组 RECORD 变量为 NULL,或者是初始化为数据库 Table 的默认值:

INITIALIZE 变量串行 { LIKE 字段串行 | TO NULL }
MAIN
	DEFINE cr RECORD LIKE customer.*
	INITIALIZE cr.cust_name TO NULL #初始化cr的cust_name字段为NULL
	INITIALIZE cr.* LIKE customer.* #初始化cr的变量为customer表的值
END MAIN

常数(CONSTANT)

一些系统预定义常数
在这里插入图片描述
定义常数CONSTANT constant_id [data_type] = value
注:定义常数可以不指定类型;系统会自动判断类型,若指定错误则会纠正。

CONSTANT c1 = "Drink" -- 自行定义为 STRING
CONSTANT c2 = 4711 -- 自行定义为 INTEGER
CONSTANT c3 SMALLINT = 12000 -- 自行纠正为 INTEGER
CONSTANT c4 CHAR(10) = "abc" --  按照定义为 CHAR(10)

运算符(operators)

比较运算符
`在这里插入图片描述

MAIN
    DEFINE a,b INTEGER
    LET a = b := 10
    DISPLAY a, b -- 10  10
END MAIN
MAIN
    DEFINE a,b INTEGER
    LET a = b = 10
    DISPLAY a,b -- 0   0
END MAIN

逻辑运算符
在这里插入图片描述
数值运算符
在这里插入图片描述

MAIN
	DEFINE i,j SMALLINT
	LET i = 9
	LET j = 2
	DISPLAY i + j	--DISPLAY 11
	DISPLAY i - j	--DISPLAY 7
	DISPLAY i * j	--DISPLAY 18
	DISPLAY i / j	--DISPLAY 4.5
	DISPLAY j ** i	--DISPLAY 512
	DISPLAY i mod j	--DISPLAY 1
END MAIN

字符串运算符
在这里插入图片描述
在这里插入图片描述
?????????
说明:表达式[start,end]表示从字符串中取出子字符串,此表示方式仅能用在 CHAR 或
VARCHAR 上
,若变量型态为 STRING,则参照如下范例:

MAIN
	DEFINE i,j STRING
	LET i = "T100"
	LET j = i.subString(1, 4)
	DISPLAY j	--T100
	DISPLAY i.subString(1, 4) --T100
END MAIN

在这里插入图片描述
关联语法(Associative syntax) 运算符
在这里插入图片描述
日期运算符
在这里插入图片描述
对话框处理 (Dialog handling)运算符
在这里插入图片描述

全局变量(GLOBALS)

语法一:直接写定 GLOBALS 区块

GLOBALS
	declaration-statement
	[,...]
END GLOBALS

语法二:读入已写好的共同配置文件(外部档案)

GLOBALS "filename"

变数的生命周期(LOCALE、MODULE、GLOBAL)

LOCAL变量(Local Variables)

  • 定义位置:定义在 Module 中的函式里 (MAIN、FUNCTION 等)
  • 生命周期:只属于该定义的函式使用,离开此函式即不能再使用。

MODULE变量(Module Variables)

  • 定义位置:Module 中,但不被任何的函式包围。
  • 生命周期:为该 Module 中的共享变数。

GLOBAL变量(Global Variables)

  • 定义位置:由 GLOBALS 及 END GLOBALS 所包围的变数。
  • 生命周期:使用的所有 MODULE 的共享变量。
SCHEMA ds

GLOBALS
	DEFINE g_employee CHAR(10) --GLOBAL
END GLOBALS

DEFINE g_tty CHAR(32) --MODULE

MAIN
	DEFINE answer CHAR(1) --LOCAL
END MAIN

FUNCTION ins_employee()
	DEFINE flag CHAR(1), --LOCAL
	change SMALLINT	--LOCAL
END FUNCTION

控制输出格式(USING)

针对 数值或日期 设定其 显示格式,设定时注意 溢出(overflow) 的问题。

数值格式标志
在这里插入图片描述
日期格式标志
在这里插入图片描述
???????????????????????

MAIN
	DEFINE i,j SMALLINT
	LET i = 12345
	LET j = -12345
	DISPLAY i
	DISPLAY j
	DISPLAY i USING"*******"
	DISPLAY j USING"*******"
	DISPLAY i USING"&&&&&&&"
	DISPLAY j USING"&&&&&&&"
	DISPLAY i USING"#######"
	DISPLAY j USING"#######"
	DISPLAY i USING"<<<<<<<"
	DISPLAY j USING"<<<<<<<"
	DISPLAY i USING"-------"
	DISPLAY j USING"-------"
	DISPLAY i USING"+++++++"
	DISPLAY j USING"+++++++"
	DISPLAY i USING"$$$$$$$"
	DISPLAY j USING"$$$$$$$"
	DISPLAY i USING"(######)"
	DISPLAY j USING"(######)"
	DISPLAY i USING"###,###.&&"
	DISPLAY j USING"###,###.&&"
END MAIN

在这里插入图片描述

MAIN
	DISPLAY TODAY
	DISPLAY TODAY USING "yyyy-mm-dd"
	DISPLAY TODAY USING "yy-mm-dd"
	DISPLAY TODAY USING "yy-mmm-ddd"
END MAIN

在这里插入图片描述

函数、流程控制

IMPORT 引入链接库(跳过)

SCHEMA / DATABASE 声明数据库

使用 SCHEMA 声明数据库时,只会在编译过程中使用到声明的功能,执行程序时并不会与数据库进行实质联机。
使用 DATABASE 声明数据库时,编译时功能相同,但执行时即会链接数据库。

在这里插入图片描述

SCHEMA ds #声明数据库ds

MAIN
	DEFINE lc_zz01 LIKE zz_file.zz01
	SELECT zz01 INTO lc_zz01 FROM zz_file WHERE zz01='tiptop'
END MAIN

???????????
注:使用 SCHEMA 指令,因此并未于实际登入数据库,执行时回报如下:

Program stopped at 'test_schema.4gl', line number 5.
SQL statement error number -1803 (-1). Connection does not exist.

MAIN 函数与设定区块

MAIN 函数是程序执行的入口,一个完整可执行的程序只能有一个 MAIN 函数。

最简单的完整作业:

MAIN
	DISPLAY "hello world!"
END MAIN

MAIN 函数可简单写成如上,也可增加一些 设定区块

DEFER 设定 可定义程序是否要拦截『当使用者按下中断(interrupt)或离开(quit)键』时所送出的系统讯号:DEFER {INTERRUPT | QUIT}

OPTIONS 设定 可变更系统默认的选项
在这里插入图片描述
Exceptions 设定 定义当遇到 SQL 错误时,系统要采什么操作。
语法格式:WHENEVER [ANY] ERROR { CONTINUE | STOP | CALL function | GOTO label }

复杂的 MAIN 函数示例:

MAIN
	OPTIONS #改变一些系统默认值
		INPUT NO WRAP, #输入的方式:不打转
		# FORM LINE FIRST + 2, #画面开始的位置
		# MESSAGE LINE LAST, #讯息显示的位置
		# PROMPT LINE LAST, #提示讯息的位置
		FIELD ORDER FORM #整个画面会依照 p_per 所设定的字段顺序
	DEFER INTERRUPT
	
	WHENEVER ERROR STOP #当发生 SQL Error 时即停止程序
	
	DISPLAY “Change Exception!”
	
	WHENEVER ERROR CALL chk_err #此处的 CALL 是没有括号的
	
END MAIN

FUNCTION chk_err( )
	DISPLAY “Error Happened!END FUNCTION

FUNCTION 函数

语法:[PUBLIC | PRIVATE ] FUNCTION function_name( [arg [ , … ] ] )

当设定为 PRIVATE 时,只限本 4gl 文件内使用;连结时在 42x 或 42r 内无法看到该函数。

MAIN
	CALL say_hello_public()
	CALL say_hello_private()
END MAIN

FUNCTION say_hello_public()
	DISPLAY "Hello, world!"
END FUNCTION

PRIVATE FUNCTION say_hello_private()
	DISPLAY "Hello, Private!"
END FUNCTION

CALL 执行指定的函数,若有回传值,以 RETURNING 接回。
语法格式:CALL function ( [ parameter [,...] ] ) [ RETURNING variable [,...] ]

RETURN 返回函数所需的变量值,并停止此函式的执行。


回传单一值

MAIN
	DEFINE var1 CHAR(10)
	DEFINE var2 CHAR(2)
	LET var1 = foo()
	DISPLAY "var1 = " || var1 -- var1 = Hello
	CALL foo() RETURNING var2
	DISPLAY "var2 = " || var2 -- var2 = He
	DISPLAY "foo() = " foo() -- foo() = Hello
END MAIN

FUNCTION foo()
	RETURN "Hello"
END FUNCTION

回传单一值(布尔):

MAIN
	IF foo() THEN
		DISPLAY "Choice is OK!END IF
END MAIN

FUNCTION foo()
	RETURN TRUE
END FUNCTION

回传多个值: 可用 RETURNING 接收

MAIN
	DEFINE var1 CHAR(15)
	DEFINE var2 CHAR(15)
	CALL foo() RETURNING var1, var2
	DISPLAY var1, var2
END MAIN

FUNCTION foo()
	DEFINE r1 CHAR(15)
	DEFINE r2 CHAR(15)
	LET r1 = "return value 1"
	LET r2 = "return value 2"
	RETURN r1, r2
END FUNCTION

文件之间互相调用:test1.4gl 调用 test2.4gl 中的函数,并且用命令行执行 test3.4gl

test1.4gl

MAIN
	DISPLAY "MAIN FUNCTION"
	CALL a1()
	CALL a2()
	RUN "fglrun test3" # 利用RUN执行命令行
END MAIN

FUNCTION a1()
	DISPLAY "SUB FUNCTION a1()"
END FUNCTION

以上程序段会呼叫另外两个 Function,并且利用 RUN 指令执行一道 unix 指令

test2.4gl

FUNCTION a2()
	# a2 function
	DISPLAY "SUB FUNCTION a2()"
END FUNCTION

test3.4gl

MAIN
	DISPLAY "This is test3.4gl"
END MAIN

报表结构 REPORT 函数(跳过)

这是一种专门用来设定报表打印格式的函数,后续章节有详细的介绍。

IF

语法:??????MATCHES 支持正则表达式?

IF condition THEN
	statement
	[...]
ELSE
	statement
	[...]
END IF
MAIN
	DEFINE name CHAR(20)
	LET name = "John Smith"
	IF name MATCHES "John*" THEN
		DISPLAY "The first name is too common to be displayed."
		IF name MATCHES "*Smith" THEN
			DISPLAY "Even the last name is too common to be displayed."
		END IF
	ELSE
		DISPLAY "The name is " , name , "."
	END IF
END MAIN

CASE

语法1格式:适用于判断式比较简单,如只需判断1个数字

CASE expression-1
	WHEN expression-2
		{ statement | EXIT CASE }
		[...]
	OTHERWISE
		{ statement | EXIT CASE }
		[...]
END CASE
MAIN
	DEFINE v CHAR(10)
	LET v = "C1"
	CASE v
		WHEN "C1"
			DISPLAY "Value is C1"
		WHEN "C2"
			DISPLAY "Value is C2"
		WHEN "C3"
			DISPLAY "Value is C3"
		OTHERWISE
			DISPLAY "Unexpected value"
	END CASE
END MAIN

语法2格式:适用于判断式较复杂

CASE
	WHEN boolean-expression
		{ statement | EXIT CASE }
		[...]
	OTHERWISE
		{ statement | EXIT CASE }
		[...]
END CASE
MAIN
	DEFINE v CHAR(10)
	LET v = "C1"
	CASE
		WHEN ( v="C1" OR v="C2" )
			DISPLAY "Value is either C1 or C2"
		WHEN ( v="C3" OR v="C4" )
			DISPLAY "Value is either C3 or C4"
		OTHERWISE
			DISPLAY "Unexpected value"
	END CASE
END MAIN

语法2注意:若有两种情况成立,系统仅会走第一条符合条件的路径。

下列代码只会显示:a is ok

MAIN
	DEFINE a,b INTEGER
	LET a = b := 10
	CASE
		WHEN a = 10 DISPLAY " a is ok "
		WHEN b = 20 DISPLAY " b is ok "
		OTHERWISE DISPLAY " nothing is ok "
	END CASE
END MAIN

FOR

语法:默认情况 STEP = 1

FOR counter = a TO b [ STEP value ]
	statement
	[...]
END FOR 
MAIN
	DEFINE i, i_min, i_max INTEGER
	LET i_min = 1
	LET i_max = 10
	
	DISPLAY "Look how well I can count from " , i_min , " to " , i_max
	DISPLAY "I can count forwards..."
	
		FOR i = i_min TO i_max # 正序
			DISPLAY i
		END FOR
		
		DISPLAY "... and backwards!"
		
		FOR i = i_max TO i_min STEP -1 #反序
			DISPLAY i
		END FOR
END MAIN

WHILE

语法:执行程序直到条件不成立为止。

WHILE b-expression
	 statement
	 [...]
END WHILE
MAIN
	DEFINE a,b INTEGER
	LET a = 20
	LET b = 1
	
	WHILE a > b
		DISPLAY a , " > " , b
		LET b = b + 1
	END WHILE
	
END MAIN

CONTINUE

语法:跳出本次循环。

CONTINUE { FOR | FOREACH | MENU | CONSTRUCT | INPUT | WHILE }
MAIN
	DEFINE i INTEGER
	LET i = 0
	WHILE i < 5
		LET i = i + 1
		DISPLAY "i = " || i
		CONTINUE WHILE
		DISPLAY "This will never be displayed !"
	END WHILE
END MAIN

EXIT

语法:离开控制段。

EXIT { CASE | FOR | MENU | CONSTRUCT | FOREACH | REPORT | DISPLAY | INPUT | WHILE | PROGRAM }
MAIN
	DEFINE i INTEGER
	LET i = 0
	
	WHILE TRUE
		DISPLAY "This is an infinite loop. How would you get out of here ?"
		LET i = i + 1
		IF i = 100 THEN
			EXIT WHILE
		END IF
	END WHILE
	
	DISPLAY "Well done."
END MAIN

TRY…CATCH

针对重要 SQL 指令可以预先设置专用的错误处理指令。

语法:

TRY
	[待侦测是否会发生问题的程序段落]
CATCH
	[处理问题或回报讯息的程序段落]
END TRY

示例:

MAIN
	LET lc_a = ARG_VAL(1)
	TRY
		DATABASE lc_a
	CATCH
		DISPLAY lc_a,' not in fglprofile, number:', SQLCA.SQLCODE
	END TRY
END MAIN

SLEEP

语法:程序依指定秒数暂停。

SLEEP seconds

注意:如果 seconds < 0 或 seconds IS NULL,则程序不会停止。

MAIN
	DISPLAY "Please wait 5 seconds..."
	SLEEP 5 #暂停5秒
	DISPLAY "Thank you."
END MAIN

LABEL 和 GOTO(❌)

为了程序的易读性和结构性,请不要使用该指令。

MAIN
	DISPLAY "Before GOTO"
	GOTO: label_id1
	DISPLAY "Never Been Displayed"
	LABEL label_id1:
	DISPLAY "After GOTO"
END MAIN

常用的内置函数(built-in functions)

在这里插入图片描述

  • 15
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

萌宅鹿同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值