ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

sdut-编译原理课程实验

sdut-编译原理课程实验 A - 小C语言--词法分析程序Description小C语言文法1. 程序→main关键字(){声明序列语句序列}2. 声明序列→声明序列声明语句|声明语句|空3. 声明语句→标识符表;4. 标识符表→标识符,标识符表|标识符5. 语句序列→语句序列语句|语句6. 语句→ if语句| while语句| for语句|复合语句|赋值语句7. if语句→ if关键字(表达式)复合语句|(表达式)复合语句 else关键字复合语句8. while语句→ while关键字(表达式)复合语句9. for语句→ for关键字(表达式;表达式;表达式)复合语句10. 复合语句→{语句序列}11. 赋值语句→表达式;12. 表达式→标识符算数表达式|布尔表达式13. 布尔表达式→算数表达式 |算数表达式关系运算符算数表达式14. 关系运算符→|||||!15. 算数表达式→算数表达式项|算数表达式-项|项16. 项→项*因子|项/因子|因子17. 因子→标识符|无符号整数|(算数表达式)18. 标识符→字母|标识符字母|标识符数字19. 无符号整数→数字|无符号整数数字20. 字母→a|b|…|z|A|B|…|Z21. 数字→0|1|2|3|4|5|6|7|8|922. main关键字→main23. if关键字→if24. else关键字→else25. for关键字→for26. while关键字→while27. int关键字→int每行单词数不超过10个小C语言文法如上现在我们对小C语言写的一个源程序进行词法分析分析出关键字、自定义标识符、整数、界符和运算符。关键字main if else for while int自定义标识符除关键字外的标识符整数无符号整数界符{ } ( ) , ;运算符 - * / !Input输入一个小C语言源程序源程序长度不超过2000个字符保证输入合法。Output按照源程序中单词出现顺序输出输出二元组形式的单词串。(单词种类,单词值)单词一共5个种类关键字用keyword表示自定义标识符用identifier表示整数用integer表示界符用boundary表示运算符用operator表示每种单词值用该单词的符号串表示。SamplesSample #1InputOutputmain() { int a, b; if(a 10) { a b; } }(keyword,main) (boundary,() (boundary,)) (boundary,{) (keyword,int) (identifier,a) (boundary,,) (identifier,b) (boundary,;) (keyword,if) (boundary,() (identifier,a) (operator,) (integer,10) (boundary,)) (boundary,{) (identifier,a) (operator,) (identifier,b) (boundary,;) (boundary,}) (boundary,})答案# 定义一个用来词法分析的函数 def analysis(source): # source就是函数的输入参数即输入的字符串 # 定义存放所有关键字、界符、运算符的集合 keywords[main,if,else,for,while,int] boundaries[{,},(,),,,;] operators[,,,!,,,-,*,/,,] # i是一个指针标志“现在读到了第几个字符”,从0开始因为字符串的第一个字符位置是0 i0 # n是字符串source的长度用来在后面判断”有没有读完“ nlen(source) # 定义一个空列表装最后的结果每识别出一个单词就往里面加一个 result[] # 如果没读到字符串末尾就一直读 while in: # 当前位置的字符 chsource[i] # 1.跳过空白如果ch是空格或\t\n\r if ch in \t\n\r: i1 # 记得continue(回到循环开头判断接下来的字符类型 continue # 2.如果是标识符或关键字 if ch.isalpha(): # 记住开始位置我们要从start开始的地方一直读不是字母的地方 starti # 判断当前字符是不是字母或数字标识符以字母开头后面可以跟字母也可以跟数字)如果是就往后移一位 while in and source[i].isalnum(): i1 # 把我们这轮while读到的所有字符拼成一个单词然后判断它在不在关键字集合里不在的话就是标识符 wordsource[start:i] if word in keywords: result.append( (keyword,word) ) else: result.append( (identifier,word) ) # 记得continue continue # 3.如果是整数 if ch.isdigit(): starti while in and source[i].isdigit(): i1 numsource[start:i] result.append( (integer,num) ) # 记得continue continue # 4.如果是界符 if ch in boundaries: result.append( (boundary,ch) ) i1 # 记得continue continue # 5.如果是运算符—— # ①先匹配双字符 # 确保后面还有一个字符 if i1n: # i:i2表示这个字符和下个字符拼成的双字符 two_charsource[i:i2] # 如果这个two_char在运算符集合里 if two_char in operators: result.append( (operator,two_char) ) # 指针需向后移动2 i2 # 别忘了continue continue # ②再匹配单字符 if ch in operators: result.append( (operator,ch) ) i1 continue # 若循环结束返回一个result return result # 主程序,注意是 if __name____main__: # 导入sys模块用来读取输入 import sys # 读取所有输入知道EOF sourcesys.stdin.read() # 调用前面定义的analysis函数将读取到的输入传进去,得到的结果存在r里 ranalysis(source) # 遍历r列表里的每一个元素每个元素只一个元组包含两个值种类type和值value for r_type,r_value in r: # 记得加括号 print((f{r_type},{r_value}))B - 识别浮点常量问题Description编译器在对程序进行编译之前首先要进行语法分析。通常程序被分解成若干个小单元然后和语言的语法模式进行匹配。在分析表达式的时候变量的类型在变量声明的时候就决定了而常量的类型需要从常量的形式来判断。假设你是自动编译器ACM开发小组的一员负责Pascal语言编译器的开发。你的任务是分析程序分解模块送来的文件判断其中包含的字符串是否合乎语法的Pascal浮点常量。Pascal语言对浮点常量的语法要求是一个浮点常量除了十进制数码之外必须带有一个小数点或一个指数紧接在字母e或E之后在正式文档中也被称为比例因子。如果该浮点常量含有小数点则在小数点两侧都至少要有一个十进制数码。当然在整个浮点常量或指数之前也许会出现符号或-。指数不能包含小数。空格也许会出现在浮点常量的前后但不会出现在浮点常量中间。请注意Pascal语言的语法规则没有对浮点数常量的取值范围作出任何假定。Input输入只有一行就是有待识别的字符串。字符串的长度不超过255。Output请将分析的结果按以下样例的格式输出。如果输入文件中的字符串是Pascal浮点常量请输出字符串“YES”否则输出字符串“NO”。SamplesSample #1InputOutput1.2YESHint输入1 输出NO输入1.0e-55 输出YES输入e-12 输出NO输入1e-12 输出YES输入6.5E 输出NO输入4.1234567890E-9999 输出: YES答案 一个Pascal浮点常量必须满足的条件 1.前后可以有空格但空格不能出现在数字中间 2.必须包含小数点 . 或指数 e/E至少一个也可以两个都有 3.如果有小数点小数点左边至少一位数字右边至少一位数字 4.如果有指数e/Ee/E前面要有数字后面必须有整数可以带或-号且指数部分不能有小数点 5.符号 或 - 只能出现在最开头或e/E后面其他地方不能出现 6.整个常量只能包含数字、、-、.、e、E 总结NO的情况有 1.整体结构类输入全是空格只有或-后面没东西既没有小数点也没有e/E小数点出现超过一次e/E出现吵过一次 2.小数点相关小数点左边没数字小数点右边没数字直接到末尾小数点右边紧挨着的就是e中间没数字 3.指数e/E相关前面没数字后面没数字e后面是或-但后面没有东西了指数部分包含非数字字符小数点也不行 4.底数部分小数点和e/E之间的部分相关出现非数字字符但小数点可以数字中间有空格 # 读取一个输入且去掉前后的空格若中间有空格则在后面会检查出来 sinput().strip() # 1.如果长度是0那么直接停止程序exit() nlen(s) if n0: print(NO) exit() # 2处理开头的- # start记录真正开始读数字的位置默认从第一个字符开始0 start0 if s[0] or s[0]-: # 如果第一个字符是或-那么真正开始读数字的位置就从1开始 start1 # 如果输入只有或-后面没有东西那么停止程序 if startn: print(NO) exit() # 3.找小数点和e/E的位置 # 先默认两者都没找到用-1表示其没找到时的位置 dot_pos-1 e_pos-1 # 指针i从start开始跳过开头可能存在的或- istart # 只要i还没走到字符串末尾就一直循环 while in: # 如果当前的字符是小数点 if s[i].: # 如果小数点之前已经出现过即dot_pos在当前if成立前已经不是-1了那么终止程序 if dot_pos!-1: print(NO) exit() # 记录小数点的位置 dot_posi # 如果当前的字符是e/E elif s[i]e or s[i]E: # 如果e/E出现超过一次停止程序 if e_pos!-1: print(NO) exit() # 记录e/E的位置 e_posi # 本轮判断完成i要往后移动一位 i1 # 4.如果既没有小数点也没有e/E终止程序 if dot_pos-1 and e_pos-1: print(NO) exit() # 5.有小数点的情况 if dot_pos!-1: # 小数点左边没数字小数点就在开头,错误 if dot_posstart: print(NO) exit() # 小数点右边没数字到达输入末尾或者右边是e,错误 if dot_pos1n or ( e_pos!-1 and dot_pos1e_pos ): print(NO) exit() # 6.有e/E的情况 if e_pos!-1: # 前面没数字错误 if e_posstart: print(NO) exit() # 后面没东西,错误 if e_pos1n: print(NO) exit() # e/E后面可以是或- # exp_start记录指数部分开始的位置 exp_starte_pos1 # 如果e后面的第一个字符是或-那么exp_start再往后移动一位 if s[exp_start] or s[exp_start]-: exp_start1 # 如果或-后没东西错误 if exp_startn: print(NO) exit() # 检查指数部分是否全是数字不是含小数点 # 从指数部分开始的地方一个个检查 iexp_start # 不能超出输入的长度 while in: # 每个字符都必须在0-9之间 if s[i]0 or s[i]9: print(NO) exit() # 全是数字就可以i1了 i1 # 7.检查小数点和e/E之间的部分底数部分是否合法 # 如果有e/E底数部分到e为止 if e_pos!-1: body_ende_pos # 如果没有e/E底数部分到输入末尾 else: body_endn # 从开头扫描到底数部分结束 istart while ibody_end: # 如果当前位置是小数点跳过它小数点不是数字不用检查 if dot_pos!-1 and idot_pos: i1 # 继续循环 continue # 如果当前字符不是数字错误 if s[i]0 or s[i]9: print(NO) exit() i1 # 如果全部通过就YES print(YES)C - 小型Basic编译器问题Description编写一个TinyBasic语言的解释程序对于任何一个给出的正确的TinyBasic语言的程序你的程序能运行它并得到正确的结果。那么怎样的TinyBasic的程序叫做正确的呢1符合TinyBasic语言的语法规则2程序执行时会产生一个或多个输出可以中断即程序不会进入无限循环状态。TinyBasic语言的语法规则1每一行的TinyBasic程序都是下面这样的形式所有出现的字母均为大写[空格]行号空格语句其中[空格]中可以有任意个空格当然也可以没有行号中一定要有行号从1开始依次递增1空格中至少有一个空格语句应为下面的语句之一LET空格变量表达式PRINT空格变量GOTO空格表达式IF空格表达式STOP2定义变量和表达式的规则为变量必须是单个的大写英文字母存储一个整数值表达式为常量 范围在[-10000…10000]内的整数常量比如0-534变量变量 两个变量所代表的是有符号整数变量变量 大于号真为1假为03表达式中和LET语句的等号两边没有空格4TinyBasic的程序最多只有100行。执行TinyBasic语言程序的规则1从程序中的第1行开始执行2程序中用到的所有变量的初始值均为03语句连续执行除非碰到IF或GOTO语句45种语句的定义LET 给变量赋值。若两个变量相加相加的结果在[-10000…10000]之内。PRINT 变量名值的格式打印变量的值。左对齐并单独占用一行行中无任何多余空格。GOTO 跳到行号为表达式的值的一行。表达式不需要是一个常量表达式的值是程序中的有效行号。IF 如果表达式的值非0继续执行下一行如果表达式的值为0跳过下一行执行下一行的下一行。在IF语句以下至少还应该有两条语句。STOP 终止执行。TinyBasic程序一定会执行到STOP语句如果你的解释程序是正确的话TinyBasic程序可能包含一个以上的STOP语句程序的最后一句不一定是STOP语句。Input输入数据只有一组包含一个程序没有多余的空行每一行为一条语句具体要求按上面的解释。你编写的程序要正确地运行该TinyBasic程序。Output输出程序的运行结果文件头尾都不需要多余空行。SamplesSample #1InputOutput1 LET A10 2 LET I0 3 LET XII 4 LET T1 5 LET XXT 6 PRINT X 7 LET T1 8 LET IIT 9 IF AI 10 GOTO 3 11 STOPX1 X3 X5 X7 X9 X11 X13 X15 X17 X19答案
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进