一 开发日志 公司从2月份从日本接了一项特殊的COBOL项目, 基本工作是从日本一家公司输送的400个COBOL源程序改成等效的其他语言的程序, 我们负责的是将COBOL源程序拟制出详细设计书, 再由日本某个软件公司的一个开发项目组根据我们的设计书用其他开发语言或者开发平台开发出等效的新程序. COBOL是一种商业开发语言. 不知道日方为什么要改写这些程序.我们把程序拿过来之后, 没有COBOL运行环境, 无法知道这些程序的运行结果是什么, 也没有以前开发这些程序的设计书. 项目起初, 我们首先是熟悉一下COBOL语法, 然后一行行读程序, 理解其中的意思, 然后写出设计书, 设计书必须详细,正确, 因为这些设计书将拿来设计等效的其他语种的程序,如果设计书错误, 重写程序就是错误的.所以项目起初十分累, 工作也相当机械, 我们曾经提议安装COBOL语言的编译环境和运行环境, 然后逐个运行这些程序, 根据运行结果,我们可以完成设计书的大部分, 而无须读程序. 然而这种想法也行不通, 日本的这组程序是运行在简单的支票打印机上的, 而不是PC机上, 所以有了软件环境,却没有硬件环境和程序所需的数据库资源. 我们觉得日本鬼子在拿我们当机器去运行这些程序,然后写出设计书, 这是极为艰苦的工作, 开发进度非常缓慢, 效率很底,大概一个人要四天才能完成一份设计书。 当时我想了一个办法, 自己编写一个专门的COBOL程序的解释机器, 解释机器不但解释执行程序,并且模拟当前的硬件环境和数据资源环境. 直接生成设计书的大部分内容, 行内的都知道, 要写一个编译程序或者解释程序是相当困难的.所以我们项目组,基本上没有人有这个想法.部门经理还说, 如果谁能开发出设计书生成器,本年度的最佳员工非他莫属. 我被这句话直接打动了, 心想,一定要把COBOL解释程序开发出来. 经过几个星期的酝酿和开发, 2006-3-8 终于出炉,并且用于开发测试当中.下面是开发日志: 全部使用Borland C++ Builder 构建. 2006-3-4 进入开发阶段, 词法分析。 2006-3-5 语法分析 2006-3-6 驱动程序, 解释执行 2006-3-7 内核完成, 用Borland C++ Builder制作交互界面。首次实验, 改进, 可 以生成式样书的数据格式部分,数据库字段部分, 对齐方式, 暴露缺陷: 无法分析共用内存, 无法分析条件判断, 数据处理的解释部分缺乏力度。 同事希望我用解释机来和熟练的员工比工作 速度和质量 2006-3-8 用优化后的解释机做022210, 速度不错。 但是出现错误。 导致停工,晚上检查内核再使用,所以才有现在的闲暇时间在这里写日志。 前几天实在太忙了。 下一个完善目标是, 解释ADD语句, 完善Redfine处理。 争取解释条件判断语句。 生成简单备注 客户发送上周已经提交的项目的修改方案,项目进入全面的修改当中。 需要修改的式样书: 0022901(日本已经指摘) 00ADJ11 00ICN10 00JMN10 本周: 00JMN10, 00KIC10, 0122201 自动机2006-3-9晚优化(版本:1.3), 1.修复接受数据类型的一个漏洞。 2.增加可以识别并正确处理公用内存功能。 3.增加准确处理空印字功能。 第二批COBOL项目从2006-2-27日 开始, 计划到2006-3-21日结束。 项目组中,我承担了147个项目中的11个, 产品代号分别是: 001_0022901_010000 瀬田スズキ : 第一批COBOL项目的开发方法 001_00AJD11_100000 AJD : 日本EXCEL宏生成大致位置 001_00ICN10_110000 IC-NET : 日本EXCEL宏生成大致位置 001_00JMN10_000010 東海流通ネットワーク: 日本EXCEL宏生成大致位置 001_00KIC10_110000 KICS : 部分使用我开发COBOL语言微型解释程序 001_0122201_010000 アルファチェン パーシャル :全部使用解释程序,解释程序优化 001_0122210_010000 アルファチェン パーシャル :全部使用解释程序 001_0021601_010000 高槻ダイコク : 全部使用解释程序 (1.4版本的 解释程序比较完善) 001_0025201_010000 さくらい薬品 : 全部使用解释程序 001_0025301_010000 ニシイチ : 全部使用解释程序 001_0084501_010010 東洋薬局 : 全部使用解释程序 需要指出的是: 0025201 显示了解释程序在条件判断能力上的不足。 0025301 在加强人工干预条件判断的处理力度下,效果和速度很好, 整个项目中BUG数目仅一个 0084501 这个项目突出显示了其机械性, 解释机游刃有余, 不仅速度快,并且质量也较好, 解释机 器有待于进一步改进, 减少人工干预, 最大限度提高工作效率。 经过长期测试和使用后再 推广应用 现在说全部完成了, 为时尚早, 接下来的5天将是长期,痛苦的修改中, 只有到了21号项目完全交付才能算完成! 二. 部分技术展示. 1. COBOL语言源程序单词识别自动机(Borland C++ Builder 6.0 开发) 自动机主要功能读入源程序单词, 过滤注释, 识别字符串 BOOL ReadToken(STRING rettoken){ enum status { start, accept, end, midstr, midsum }; enum status statu = start; char chr = EOF; static char cache = EOF; int i = 0; memset(rettoken,'\0',64); while (statu != end) { if (cache == EOF) { chr = Readchar(); } else { chr = cache; cache = EOF; } if ( chr == EOF ) { statu = end; } switch (statu) { case start: if (chr == '*') { statu = midsum; } else if (IsSpace(chr)) { statu = start; } else if (chr == EOF) { statu = end; } else if (chr == '.' || chr == '\n') { rettoken[i++] = chr; statu = end; } else if (IsQuote(chr)) { rettoken[i++] = chr; statu = midstr; } else { rettoken[i++] = chr; statu = accept; } break; case accept: if ( IsSpace(chr) || chr == '\n') { statu = end; } else if (chr == '*') { statu = midsum; } else if (chr == '.') { cache = chr; statu = end; } else { rettoken[i++] = chr; statu = accept; } break; case midstr: if ( IsQuote(chr)) { rettoken[i++] = chr; statu = end; } else if ( chr == '\n') { statu = end; } else { rettoken[i++] = chr; statu = midstr; } break; case midsum: if ( chr == '\n' ) { cache = chr; statu = end; } else { statu = midsum; } break; } } return chr != EOF;} 2. COBOL语言变量识别器, 前提工作是单词识别机读入的合法单词.变量识别器将进行属性求值, 记录变量属性. BOOL IsVariable(Variable *arg, char token[]){ enum Status { accept, error, start, end }; enum Status statu = start; int i = 0; strcpy(arg->text, ""); strcpy(arg->valstr,""); arg->bitcount = 0; while (token[i]) { switch (statu) { case start: if (IsAlphabet(token[i])) { statu = accept; } else { statu = error; } break; case accept: if (IsAlphabet(token[i]) || IsNumber(token[i]) || token[i] == '-') { statu = accept; } else if (token[i] == '.') { statu = end; } else { statu = error; } break; case error: statu = error; break; case end: statu = error; break; } i++; } if ( statu == end || statu == accept) { strcpy( arg->text , token); if (!strcmp(arg->text,"ZERO")) { strcpy(arg->valstr,"0"); } if (!strcmp(arg->text,"SPACE")) { strcpy(arg->valstr," "); } if (statu == end) { arg->type = cst; } return TRUE; } return FALSE;} 3.COBOL语言变量定义语句的语法分析与属性求值. BOOL DataDefineStatement(VariableRecord *arg)/*变量定义语句语法分析,解释执行*/{ Variable tempv; Variable tempcv; VariableRecord *ndfptr; long tempn; long tempcn; long tempnu; Token tempt; KeyWord tempk; VarFormat tempvf; String temps; char token[64]=""; (arg->var).type = 0; strcpy((arg->var).text,""); (arg->var).bitcount = 0; strcpy((arg->var).valstr,""); strcpy(arg->format ,""); arg->father = NULL; arg->childcnt = 0; arg->layer = 0; arg->marked = 0; if (!IsNumeric(&tempn,GetTop(TokenStackInstance))) /*行号判断*/ { return FALSE; } else {/*层次设定*/ arg->layer = tempn; if (VarTabPtr == 0) { arg->father = NULL; } else if ( tempn > VariableTable[VarTabPtr-1].layer) { arg->father = VariableTable + VarTabPtr - 1; if (arg->father->var.type == rdf) { /* printf("redfine");*/ } } else if (tempn < VariableTable[VarTabPtr-1].layer) { ndfptr = &VariableTable[VarTabPtr-1]; while ( arg->layer < ndfptr->layer ) { ndfptr = ndfptr->father; } arg->father = ndfptr->father; } else { arg->father = VariableTable[VarTabPtr-1].father; } } if (!ReadToken(token)) { return FALSE; } Push(&TokenStackInstance,token); if (!IsVariable(&tempv,GetTop(TokenStackInstance))) /*变量标识符判断*/ { return FALSE; } else {/*变量名设定*/ arg->var = tempv; } if (!ReadToken(token)) { return FALSE; } Push(&TokenStackInstance,token); if (IsDot(GetTop(TokenStackInstance))) /*结构体判断*/ {/*结构类型设定,插入到表中,识别结构体内部的所有字段*/ (arg->var).type = cst; InsertToVarTab(*arg); return TRUE; } else if (IsKeyWord(&tempk,GetTop(TokenStackInstance)) /*非结构类型变量判断*/ && tempk.type == Pic) { if (!ReadToken(token)) { return FALSE; } Push(&TokenStackInstance,token); if (IsVarFormat (&tempvf,GetTop(TokenStackInstance))) /*变量存储空间,类型判断*/ {/*存储格式设定*/ (arg->var).type = tempvf.type; (arg->var).bitcount = tempvf.bitcount; strcpy(arg->format,tempvf.text); } else {/*格式错误*/ return FALSE; } if (!ReadToken(token)) { return FALSE; } Push(&TokenStackInstance,token); if (IsDot(GetTop(TokenStackInstance))) {/*变量类型确定,存储格式确定,插入到表中*/ InsertToVarTab(*arg); return TRUE; } /* if (!ReadToken(token)) { return FALSE; } Push(&TokenStackInstance,token);*/ else if (IsKeyWord(&tempk,GetTop(TokenStackInstance)) /*变量赋初始化判断*/ && (tempk.type == Value || tempk.type == Va)) { if (!ReadToken(token)) { return FALSE; } Push(&TokenStackInstance,token); if ((arg->var).type == str && IsString(&temps,GetTop(TokenStackInstance))) /*字符串常量初始化字符串判断*/ { strcpy((arg->var).valstr,temps.text); if (!ReadToken(token)) { return FALSE; } Push(&TokenStackInstance,token); if (IsDot(GetTop(TokenStackInstance))) {/*字符串变量初始值设定,变量插入表中*/ InsertToVarTab(*arg); return TRUE; } else {/*字符串初始化错误*/ return FALSE; } } else if (IsKeyWord(&tempk,GetTop(TokenStackInstance)) && tempk.type == All) /*COBOL语言 ALL类型初始化字符串判断*/ { if (!ReadToken(token)) { return FALSE; } Push(&TokenStackInstance,token); if (IsString(&temps,GetTop(TokenStackInstance))) /*ALL后跟字符串常量判断*/ { strcpy((arg->var).valstr,temps.text); if (!ReadToken(token)) { return FALSE; } Push(&TokenStackInstance,token); if (IsDot(GetTop(TokenStackInstance))) {/*字符串变量初始值设定,变量插入表中*/ InsertToVarTab(*arg); return TRUE; } else {/*字符串初始化错误*/ return FALSE; } } else {/*字符串初始化错误*/ return FALSE; } } else if (IsVariable(&tempcv,GetTop(TokenStackInstance))) /*变量初始化变量判断*/ { if (!ReadToken(token)) { return FALSE; } Push(&TokenStackInstance,token); if (IsDot(GetTop(TokenStackInstance))) {/*变量值初始化设定,插入到表中*/ strcpy((arg->var).valstr,tempcv.valstr); InsertToVarTab(*arg); return TRUE; } else {/*初始化格式错误*/ return FALSE; } } else if (IsNumeric(&tempcn,GetTop(TokenStackInstance))) /*数值常量初始化变量判断*/ { if (!ReadToken(token)) { return FALSE; } Push(&TokenStackInstance,token); if (IsDot(GetTop(TokenStackInstance))) {/*变量初始化值设定,插入到表中*/ strcpy((arg->var).valstr,ToString(tempcn)); InsertToVarTab(*arg); return TRUE; } else {/*初始化格式错误*/ return FALSE; } } } else if (!strcmp(GetTop(TokenStackInstance),"BLANK")) { InsertToVarTab(*arg); } } else if (IsKeyWord(&tempk,GetTop(TokenStackInstance)) && tempk.type == Redefines) /*重复定义型判断*/ { (arg->var).type = rdf; InsertToVarTab(*arg); return TRUE; } return FALSE; } 4.支票打印的模拟解释执行器 BOOL Execute(){ long linecnt = ToNumber(SystemVarTab[2].var.valstr); int i = 0; VariableRecord tvr ; VarFormat tempvf; char posstr[5] =""; int j = 0; tvr.marked = 0; switch (SystemVarTab[3].var.type) { case str: printf("[%02d,%03d] %s\n",row,col, !strcmp(SystemVarTab[3].var.valstr," ")? "------BLANK LINE-----": SystemVarTab[3].var.valstr); break; case rdf: case cst: for ( i = 0; i < VarTabPtr; i++) { if (!strcmp(VariableTable[i].var.text, SystemVarTab[3].var.valstr)) { break; } } for ( j = 0; j < VariableTable[i].childcnt; j++ ) { tvr = *(VariableTable[i].child[j]); if (tvr.var.type == num || tvr.var.type == str) { tempvf.type = tvr.var.type; strcpy(tempvf.text,tvr.format); tempvf.bitcount = tvr.var.bitcount; FormatToExcel(&tempvf); strcpy(tvr.format,tempvf.text); if (strcmp(tvr.var.text,"FILLER") || tvr.father->var.type == rdf || strcmp(tvr.var.valstr," ")) { strcpy(posstr,GetSubpenaPos(row, col)); if (strcmp(posstr,"")) { printf("%8s ",posstr); } else { printf("[%02d,%03d] ",row,col); } } if (tvr.father->var.type != rdf) { col += tvr.var.bitcount; } TOExcel(tvr.var.valstr); if (strcmp(tvr.var.text,"FILLER") || tvr.father->var.type == rdf || strcmp(tvr.var.valstr," ")) { printf("%-24s %-24s ", tvr.var.text, strcmp(tvr.var.valstr,"")? !strcmp(tvr.var.valstr," ")? "SPACE":tvr.var.valstr : tvr.var.text); printf(" %10s 10.8Pt %s %s %s\n",tvr.format, tvr.var.type == num ? "=>":"<=", tvr.father->var.type == rdf ? "REDF":"", VariableTable[i].child[j]->marked > 1? "MARK":"" ); } } else { strcpy(SystemVarTab[3].var.valstr,tvr.var.text); strcpy(SystemVarTab[2].var.valstr, "0"); SystemVarTab[3].var.type = tvr.var.type; Execute(); } } break; } row += linecnt; return TRUE;} 5. 解释器的外壳, GUI void __fastcall TForm1::Button2Click(TObject *Sender){ char command[128] = "CBPRJGEN "; if (this->Edit1->Text == "") { ShowMessage("Must input the filename."); this->Edit1->Focused(); return; } strcat(command, this->Edit1->Text.c_str()); //导入内核, 源程序 strcat(command,"> 0310res.txt"); system(command); // 启动解释程序 system("NotePad 0310res.txt"); // 展示解释运行的结果.}//--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender){ this->OpenDialog1->Filter = "*.TXT"; this->Edit1->Text = ""; this->OpenDialog1->DefaultExt = "*.TXT"; //this->OpenDialog1->InitialDir = this->GetNamePath(); this->OpenDialog1->Execute(); AnsiString temp = this->OpenDialog1->FileName; char str[16] = ""; int j = 0; for (int i = temp.Length(); i > 0; i--) { if (temp[i] != '\\') { str[j++] = temp[i]; } else { strrev(str); break; } } AnsiString x(str); this->Edit1->Text = x; } 附: 本程序的运行时的GUI截图

评论