合肥工业大学编译原理实验LL(1)完整Scala实现代码与测试数据
github项目地址:https://github.com/25thengineer/Compile_Experiment_LL_1
完成了形式上的消除左递归,但是还存在bug,不能直接用于求解实际问题,但过实验指导书的样例是没问题的。先上几组测试数据。
测试数据:
test.data(指导书上的样例):
1 E->TG
2 G->+TG|-TG
3 G->ε
4 T->FS
5 S->*FS|/FS
6 S->ε
7 F->(E)
8 F->i
test2.data:
1 E->E+T|T
2 T->T-T|F
3 T->T+T|x
4 F->(E)|i
test3.data:
1 E->TG
2 G->+TG|-TG
3 G->ε
4 S->*FS|/FS
5 S->ε
6 F->(E)
7 F->i
8 T->α
9 α->Sα|ε
test4.data:
1 E->EG|HR
2 G->+TG|-TG
3 G->ε
4 T->FS
5 E->ES|HR
6 S->*FS|/FS
7 S->ε
8 F->(E)
9 F->i
test5.data(书上的例子):
1 E->E+T|T
2 T->T*F|F
3 F->(E)|i
下面直接上代码,如果后面有时间而且心情好的话再修修补补下。老师要求有个界面,我因为对Scala的GUI编程不熟悉,没有弄;虽说Scala的GUI编程与Java的一脉相承,但差别还是有的,如果直接把Java的代码放在Scala里面跑铁定是一堆error和warnning。
无GUI的代码:
1 import scala.collection.mutable
2 import scala.collection.mutable.{ArrayBuffer, Map}
3 import scala.util.matching.Regex
4
5
6
7
8 object LL1_try_GUI {
9 private final var allCharacters = new String()
10 private final var relations = new ArrayBuffer[ (String, String, String) ]()
11 private final var VN = new String()
12 private final var VT = new String()
13 private final var LL1_G = new ArrayBuffer[ (String, String) ]()
14 //private val allCandidateLetters = "αΑβΒγΓδΔεΕζΖηΗθΘιΙκΚλΛμΜνΝξΞοΟπΠρΡσΣτΤυΥφΦχΧψΨωΩ" + "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"
15 private val allCandidateLetters = "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩABCDEFGHIJKLMNOPQRSTUVWXYZ"
16 private final var usedCharacters = ""
17 // private val LL1_G = ArrayBuffer( ("E", "TG"), ("G", "+TG|-TG"), ("G", "ε"), ("T", "FS"), ("S", "*FS|/FS"),
18 // ("S", "ε"), ("F", "(E)"), ("F", "i") )//, ("Y", "*FS|/FS"), ("Y", "+TG|-TG"), ("Y", "x"), ("Y", "M"), ("M", "i"), ("M", "ε") )
19 // test data 1:
20 // ( ("E", "TG"), ("G", "+TG|-TG"), ("G", "ε"), ("T", "FS"), ("S", "*FS|/FS"),
21 // ("S", "ε"), ("F", "(E)"), ("F", "i"), ("Y", "S"), ("Y", "Gx"), ("Y", "x"), ("Y", "M"), ("M", "i"), ("M", "ε") )
22 // test data 2:
23 // ( ("D", "*FD"), ("D", "ε"), ("T", "FD"), ("E", "TC"), ("F", "(E)"), ("F", "i"), ("C", "+TC"), ("C", "ε") )
24 // test data 3:
25 // ( ("E", "E+T|T"), ("T", "T*F|T"), ("F", "(E)|i") )
26 // stand test data:
27 // ( ("E", "TG"), ("G", "+TG|-TG"), ("G", "ε"), ("T", "FS"), ("S", "*FS|/FS"), ("S", "ε"), ("F", "(E)"), ("F", "i") )
28
29 def main(args: Array[String]): Unit = {
30
31 //test countLines
32 //println( "cnt = " + countLines( readFromTxtByLine("/home/hadoop001/Desktop/test.data") ) )
33 //test parseFile
34 val result = parseFile("/home/hadoop001/Desktop/test.data")
35 println( "the original language rules:" )
36 for( rs <- result ) {
37 println( rs._1 + "->" + rs._2 )
38 }
39 initiate("/home/hadoop001/Desktop/test.data")
40 println( "after eliminating the all the left recursion in the language rules:" )
41 displayRelations()
42
43 println( "VT = " + VT )
44 println( "VN = " + VN )
45 println( "allCharacters = " + allCharacters )
46
47 println("*************")
48
49 val testMatrix1 = initiateMatrix()
50 for( i <- 0 to (testMatrix1.length - 1) ) {
51 for( j <- 0 to (testMatrix1(0).length - 1) ) {
52 print(testMatrix1(i)(j) + " ")
53 }
54 println()
55 }
56
57 println("*************")
58
59 // test FIRST
60 val tx = FIRST(LL1_G)
61 println( "FIRST: " )
62 for( t <- tx ) {
63 if( allCharacters.contains( t._1 ) ) {
64 println(t)
65 }
66 }
67 // test FOLLOW
68 val ex = FOLLOW(LL1_G)
69 println( "FOLLOW: " )
70 for( t <- ex ) {
71 if( VN.contains( t._1 ) ) {
72 println(t)
73 }
74 }
75
76
77
78 println("*************")
79
80 val testMatrix2 = createMatrix()
81 for( i <- 0 to (testMatrix2.length - 1) ) {
82 for( j <- 0 to (testMatrix2(0).length - 1) ) {
83 print(testMatrix2(i)(j) + " ")
84 }
85 println()
86 }
87
88 println("*************")
89
90 for( i <- 0 to (testMatrix1.length - 1) ) {
91 for( j <- 0 to (testMatrix1(0).length - 1) ) {
92 if( i == 0 && j == 0 ) {
93 testMatrix1(i)(j) = " "
94 }
95 }
96 }
97 println()
98 for( i <- 0 to (testMatrix1.length - 1) ) {
99 for( j <- 0 to (testMatrix1(0).length - 1) ) {
100 if( testMatrix1(i)(j) == null && i != 0 && j != 0 ) {
101 print(" ")
102 }
103 else {
104 print(testMatrix1(i)(j) + " ")
105 }
106 }
107 println()
108 }
109
110 analyse("i+i*i#")
111 }
112
113 /*
114 * Function name: initiate
115 * Function description: 初始化全局变量
116 * Input parameters: the absolute path of the language-rule source file
117 * Return value: 无
118 * Exception: 未处理
119 * Author: 来自高山
120 * Created date: Sat Oct 19 2019 +0800
121 * Editor: 来自高山
122 * Edited Date: Sat Oct 19 2019 +0800
123 */
124 def initiate( filePath: String ): Unit = {
125 LL1_G = parseFile(filePath)
126 allCharacters = getWholeCharacters(LL1_G)
127 usedCharacters = allCharacters
128 relations = getRelation(LL1_G)
129 VN = getVN(allCharacters)
130 VT = getVT(allCharacters)
131 eliminateLeftRecursion // eliminate all the left recursion at first
132 }
133
134 /*
135 * Function name: displayRelations
136 * Function description: display all he language rules
137 * Input parameters: 无
138 * Return value: 无
139 * Exception: 未处理
140 * Author: 来自高山
141 * Created date: Sat Oct 19 2019 +0800
142 * Editor: 来自高山
143 * Edited Date: Sat Oct 19 2019 +0800
144 */
145 def displayRelations(): Unit = {
146 for( ex <- relations ) {
147 if( ex._3 != "א" ) {
148 println( ex._1 + "->" + ex._2 + "|" + ex._3 )
149 }
150 else {
151 println( ex._1 + "->" + ex._2 )
152 }
153 }
154 }
155
156 /*
157 * Function name: parseFile
158 * Function description: 解析文本文件,保存在数组中
159 * Input parameters: 文本绝对路径
160 * Return value: -ArrayBuffer[ ( String, String ) ](String类型的元组ArrayBuffer数组)
161 * Exception: 未处理
162 * Author: 来自高山
163 * Created date: Fri Oct 18 2019 +0800
164 * Editor: 来自高山
165 * Edited Date: Fri Oct 18 2019 +0800
166 */
167 def parseFile( filePath: String ): ArrayBuffer[ ( String, String ) ] = {
168 val result = new ArrayBuffer[ ( String, String ) ]( countLines( readFromTxtByLine(filePath) ) )
169 val sourceFile = readFromTxtByLine(filePath) //filePath
170 for( line <- sourceFile ) {
171 val tmp = line.split( "->", 2 )
172 result += ( ( tmp.head, tmp.last ) )
173 }
174 result
175 }
176
177 /*
178 * Function name: countLines
179 * Function description: 计算文本行数,用于创建接收数组时开辟相应空间
180 * Input parameters: -Array[String](文本文件数据构成的数组)
181 * Return value: -Int(文本行数)
182 * Exception: 未处理
183 * Author: 来自高山
184 * Created date: Fri Oct 18 2019 +0800
185 * Editor: 来自高山
186 * Edited Date: Sat Oct 19 2019 +0800
187 */
188 def countLines( sourceFile: Array[String] ): Int = {
189 var cnt = 0
190 for( line <- sourceFile ) {
191 cnt += 1
192 }
193 cnt
194 }
195
196 /*
197 * Function name: readFromTxtByLine
198 * Function description: 读取文本文件
199 * Input parameters: -String(文本文件绝对路径)
200 * Return value: -Array[String](文本文件构成的数组,每行数据占一个数组元素)
201 * Exception: -未处理
202 * Author: 来自高山
203 * Created date: Fri Oct 18 2019 +0800
204 * Editor: 来自高山
205 * Edited Date: Fri Oct 18 2019 +0800
206 */
207 def readFromTxtByLine(filePath: String): Array[String] = {
208 import scala.io.Source
209 val source = Source.fromFile(filePath, "UTF-8")
210 //val lineIterator = source.getLines()
211 //lineIterator.foreach()
212 val lines = source.getLines().toArray
213 source.close()
214 //println(lines.size)
215 lines
216 }
217
218 /*
219 * Function name: getWholeCharacters
220 * Function description: 获取文法的除“|”之外的所有字符
221 * Input parameters: -ArrayBuffer[ (String, String) ](由文法左右两部分字符构成一个元组的数组,筛掉“|”)
222 * Return value: -String(文法的除“|”之外的所有字符)
223 * Exception: 未处理(有出错提示)
224 * Author: 来自高山
225 * Created date: Fri Oct 11 2019 +0800
226 * Editor: 来自高山
227 * Edited Date: Fri Oct 11 2019 +0800
228 */
229 def getWholeCharacters( string: ArrayBuffer[ (String, String) ] ): String = {
230 var wholeCharacters = ""
231 for( expression <- string ) {
232 wholeCharacters += expression._1 + expression._2
233 }
234 val pattern = new Regex("\\|")
235 val result = pattern replaceAllIn( wholeCharacters, "" )
236 if( result.isEmpty )
237 "function getWholeCharacters failed"
238 else
239 result.distinct
240 }
241 /*
242 * Function name: getVN
243 * Function description: 获取文法的所有非终结符(non-terminal character),默认大写字母为非终结符,使用正则表达式匹配
244 * Input parameters: -String(函数getWholeCharacters传来的文法的所有字符)
245 * Return value: -String(文法的所有非终结符)
246 * Exception: 未处理(有出错提示)
247 * Author: 来自高山
248 * Created date: Fri Oct 11 2019 +0800
249 * Editor: 来自高山
250 * Edited Date: Fri Oct 11 2019 +0800
251 */
252 def getVN( string: String ): String = {
253 //match big letter:
254 //^[A-Z]+$
255 val pattern = new Regex("[A-Z]")//("^[A-Z]+$")
256 if( (pattern findAllIn string) != null )
257 (pattern findAllIn string).mkString("")
258 else
259 "function getVN failed"
260 }
261
262 /*
263 * Function name: getVT
264 * Function description: 获取文法的所有非终结符(terminal character),默认大写字母外的字符为终结符,使用正则表达式匹配
265 * Input parameters: -String(函数getWholeCharacters传来的文法的所有字符)
266 * Return value: -String(文法的所有终结符)
267 * Exception: 未处理(有出错提示)
268 * Author: 来自高山
269 * Created date: Fri Oct 11 2019 +0800
270 * Editor: 来自高山
271 * Edited Date: Fri Oct 11 2019 +0800
272 */
273 def getVT( string: String ): String = {
274 val pattern1 = new Regex("[A-Z]")
275 val pattern2 = new Regex("\\|")
276 val firstFilter = pattern1 replaceAllIn( string, "" )
277 val result = pattern2 replaceAllIn( firstFilter, "" )
278 if( result.isEmpty == false )
279 result
280 else
281 return "function getVT failed"
282 }
283 /*
284 * Function name: getRelation
285 * Function description: 获取文法每一行对应的推导关系,若文法只推出了1项(即没有符号“|”),则返回元组的第三个用希伯来字母“א”示空
286 * Input parameters: -ArrayBuffer[ (String, String)(已经分割好的文法左右部分构成的数组)
287 * Return value: -ArrayBuffer[ (String, String, String) ](元组第一个元素为推导式左边符号,第二为右边第二个符号串,第三为右边(若有)第三个符号串)
288 * Exception: 未处理
289 * Author: 来自高山
290 * Created date: Fri Oct 11 2019 +0800
291 * Editor: 来自高山
292 * Edited Date: Fri Oct 11 2019 +0800
293 */
294 def getRelation( string: ArrayBuffer[ (String, String) ] ): ArrayBuffer[ (String, String, String) ] = {
295 val relation = new ArrayBuffer[ (String, String, String) ]()
296 for( expression <- string ) {
297 if( expression._2.contains("|") == false ) {
298 relation += ( ( expression._1, expression._2, "א" ) )
299 }
300 else {
301 val tmp = expression._2.split("\\|", 2 )
302 relation += ( ( expression._1, tmp.head, tmp.last ) )
303 }
304 }
305 relation
306 }
307
308 /*
309 * Function name: findFirst
310 * Function description: 获取指定字符的右边两个(可能是一个)导出字符串的首个非 ε 组成的字符串
311 * Input parameters: -String(指定字符)
312 * Return value: -String(指定字符的右边两个(可能是一个)导出字符串的首个非 ε 组成的字符串)
313 * Exception: 未处理
314 * Author: 来自高山
315 * Created date: Fri Oct 11 2019 +0800
316 * Editor: 来自高山
317 * Edited Date: Fri Oct 11 2019 +0800
318 */
319 def findFirst( ch: String ): String = {
320
321 val localRelations = relations
322 var result = ""
323 for( ex <- localRelations ) {
324 if( ch == ex._1 ) {
325 if( ex._3 != "א" ) {
326 if( VT.contains( ex._2(0) ) && ex._2(0) != 'ε' ) {
327 result += ex._2(0).toString
328 }
329 if( VT.contains( ex._3(0) ) && ex._3(0) != 'ε' ) {
330 result += ex._3(0).toString
331 }
332 }
333 else {
334 if( VT.contains( ex._2(0) ) && ex._2(0) != 'ε' ) {
335 result += ex._2(0).toString
336 }
337 }
338 }
339 }
340 result
341 }
342
343 /*
344 * Function name: judgeOnlyOneVoidSuccession
345 * Function description: 判断指定字符是否可推出唯一的字符ε
346 * Input parameters: -String(指定字符串)
347 * Return value: -Boolean(存在则true,否则false)
348 * Exception: 未处理
349 * Author: 来自高山
350 * Created date: Fri Oct 11 2019 +0800
351 * Editor: 来自高山
352 * Edited Date: Fri Oct 11 2019 +0800
353 */
354 def judgeOnlyOneVoidSuccession( ch: String ): Boolean = {
355 val localRelations = relations
356 var result = 1
357 for( ex <- localRelations ) {
358 if( ch == ex._1 ) {
359 if( ex._3 != "א" ) {
360 if( ( ex._2.length == 1 && ex._2(0) == 'ε' ) || (ex._3.length == 1 && ex._3(0) == 'ε') ) {
361 result = 1
362 }
363 else {
364 result = 0
365 }
366 }
367 else {
368 if( ( ex._2.length == 1 && ex._2(0) == 'ε' ) ) {
369 result = 1
370 }
371 else {
372 result = 0
373 }
374 }
375 }
376 }
377 if( result == 1 ) true else false
378 }
379
380 /*
381 * Function name: judgeCaseXY
382 * Function description: 判断构造FIRST集时可能的第3种情况的(1),即若X->Y...是一个产生式且Y∈VN(省略若干描述)
383 * Input parameters: -Char(指定字符,即可能满足条件的产生式的左边字符)
384 * Return value: -Boolean(满足则true,否则false)
385 * Exception: 未处理
386 * Author: 来自高山
387 * Created date: Sat Oct 12 2019 +0800
388 * Editor: 来自高山
389 * Edited Date: Sat Oct 12 2019 +0800
390 */
391 def judgeCaseXY( ch: Char ): Boolean = {
392 val localVN = VN
393 val localRelations = relations
394 var result = 0
395 if( localVN.contains(ch) == true ) {
396 for( ex <- localRelations ) {
397 if( ex._1(0) == ch ) {
398 if( localVN.contains( ex._2(0) ) || localVN.contains( ex._3(0) ) ) {
399 result += 1
400 }
401 }
402 }
403 }
404 if( result > 0 )
405 true
406 else
407 false
408 }
409
410 /*
411 * Function name: findCase_Y_In_XY
412 * Function description: 获取构造FIRST集时可能的第3种情况的(1),即若X->Y...是一个产生式且Y∈VN(省略若干描述)时的Y
413 * Input parameters: -Char(指定字符,即可能满足条件的产生式的左边字符)
414 * Return value: -String(Y构成的String字符串,无则为空)
415 * Exception: 未处理
416 * Author: 来自高山
417 * Created date: Sat Oct 12 2019 +0800
418 * Editor: 来自高山
419 * Edited Date: Sat Oct 12 2019 +0800
420 */
421 def findCase_Y_In_XY( ch: Char ): String = {
422 val localVN = VN
423 val localRelations = relations
424 var result = ""
425 if( localVN.contains(ch) == true ) {
426 for( ex <- localRelations ) {
427 if( ex._1(0) == ch ) {
428 if( ex._3 != "א" ) {
429 if( localVN.contains( ex._2(0) ) == true ) {
430 result += ex._2(0).toString
431 }
432 if( localVN.contains( ex._3(0) ) == true ) {
433 result += ex._3(0).toString
434 }
435 }
436 else {
437 if( localVN.contains( ex._2(0) ) == true ) {
438 result += ex._2(0).toString
439 }
440 }
441 }
442 }
443 }
444 result
445 }
446
447 /*
448 * Function name: findCase_Y_In_nY
449 * Function description: 获取构造FIRST集时可能的第3种情况的(2)时的FIRST(Yi)中所有的非ε-元素(省略描述若干字)
450 * Input parameters: -Char(指定字符,即可能满足条件的产生式的左边字符)
451 * Return value: -String(FIRST(Yi)中所有的非ε-元素构成的String字符串,无则为空)
452 * Exception: 未处理
453 * Author: 来自高山
454 * Created date: Sat Oct 12 2019 +0800
455 * Editor: 来自高山
456 * Edited Date: Sat Oct 12 2019 +0800
457 */
458 def findCase_Y_In_nY( ch: Char ): String = {
459 val localVN = VN
460 val localRelations = relations
461 var result = ""
462 for( ex <- localRelations ) {
463 if (ex._1 == ch.toString) {
464 var tmp = ""
465
466 if (ex._3 != 'א') {
467 var cnt = 0
468 for (tx <- ex._2) {
469 // add the element belongs to tmp
470 if (localVN.contains(tx)) {
471 tmp += tx.toString
472 cnt += 1
473 }
474 // otherwise, reset tmp as empty string
475 else {
476 tmp = ""
477 }
478 }
479 if (cnt == ex._2.length) {
480 result += tmp
481 }
482
483 // reset
484 cnt = 0
485 tmp = ""
486 for (tx <- ex._3) {
487 // add the element belongs to tmp
488 if (localVN.contains(tx)) {
489 tmp += tx.toString
490 cnt += 1
491 }
492 // otherwise, reset result as empty string
493 else {
494 tmp = ""
495 }
496 }
497 if (cnt == ex._3.length) {
498 result += tmp
499 }
500 }
501 else {
502 tmp = ""
503 var cnt = 0
504 for (tx <- ex._2) {
505 // add the element belongs to tmp
506 if (localVN.contains(tx)) {
507 tmp += tx.toString
508 cnt += 1
509 }
510 // otherwise, reset tmp as empty string
511 else {
512 tmp = ""
513 }
514 }
515 if (cnt == ex._2.length) {
516 result += tmp
517 }
518 }
519 }
520 }
521 result = result.distinct
522 result
523 }
524
525 /*
526 * Function name: FIRST
527 * Function description: 按照教材P78左下角的算法描述实现求解指定文法FIRST集;因用的是循环迭代求解,因此代码较长
528 * Input parameters: -ArrayBuffer[ (String, String) ](产生式左右两部分分别构成元组的第1个和第2个元素)
529 * Return value: -Map[ String, String ](Map的key是非终结符,value是其FIRST元素)
530 * Exception: 未处理
531 * Author: 来自高山
532 * Created date: Mon Oct 14 2019 +0800
533 * Editor: 来自高山
534 * Edited Date: Sat Oct 19 2019 +0800
535 */
536 def FIRST( string: ArrayBuffer[ (String, String) ] ): Map[ String, String ] = {
537 val FIRST_Group = Map[ String, String ]()
538
539 val wholeCharacters = allCharacters
540 val localVT = VT
541 val localVN = VN
542
543 for( character <- wholeCharacters ) {
544 // case 1
545 if( localVT.contains(character) ) {
546 //if there exist the original key that equals the current one
547 if( FIRST_Group.contains(character.toString) == true ) {
548 val tmp = character.toString + FIRST_Group(character.toString)
549 FIRST_Group(character.toString) = tmp.distinct
550 }
551 //otherwise
552 else {
553 FIRST_Group(character.toString) = character.toString
554 }
555 }
556
557 // case 2
558 if( localVN.contains(character.toString) == true ) {
559 // case 2.1
560 val value = findFirst(character.toString)
561 if ( value.length != 0 ) {
562 if ( FIRST_Group.contains(character.toString) == true ) {
563 for( ch <- value ) {
564 val tmp = ch + FIRST_Group(character.toString)
565 FIRST_Group(character.toString) = tmp.distinct
566 }
567 }
568 else {
569 FIRST_Group(character.toString) = value.toString
570 }
571 }
572
573 // case 2.2
574 if( judgeOnlyOneVoidSuccession(character.toString) == true ) {
575 if ( FIRST_Group.contains(character.toString) == true ) {
576 val tmp = "ε" + FIRST_Group(character.toString)
577 FIRST_Group(character.toString) = tmp.distinct
578 }
579 else {
580 FIRST_Group(character.toString) = "ε"
581 }
582 }
583 }
584
585 for( character <- wholeCharacters ) {
586 // case 3
587 // case 3.1
588 if( judgeCaseXY(character) == true ) {
589 val tmpReply = findCase_Y_In_XY(character)
590 for( eachTmpReply <- tmpReply ) {
591 if( FIRST_Group.contains(eachTmpReply.toString) == true ) {
592 for (ex <- FIRST_Group(eachTmpReply.toString)) {
593 if (ex != 'ε') {
594 if (FIRST_Group.contains(character.toString) == true) {
595 val tmp = ex.toString + FIRST_Group(character.toString)
596 FIRST_Group(character.toString) = tmp.distinct
597 }
598 else {
599 FIRST_Group(character.toString) = ex.toString
600 }
601 }
602 }
603 }
604 }
605 }
606
607 // case 3.2
608 if( findCase_Y_In_nY(character).length > 0 ) {
609 var flag = true
610 val tmpReply = findCase_Y_In_nY(character)
611
612 for( ex <- tmpReply ) {
613 if( localVN.contains(ex.toString) && FIRST_Group.contains(ex.toString) == true ) {
614 if( FIRST_Group(ex.toString).contains("ε") == false ) {
615 flag = false
616 }
617 }
618 else {
619 flag = false
620 }
621 if( flag == true ) {
622 if (FIRST_Group.contains(character.toString) == true) {
623 val tmp = FIRST_Group(ex.toString).replace( "ε", "" ) + FIRST_Group(character.toString)
624 FIRST_Group(character.toString) = tmp.distinct
625 }
626 else {
627 FIRST_Group(character.toString) = FIRST_Group(ex.toString).replace( "ε", "" )
628 }
629
630 }
631 }
632 }
633 // case 3.3
634 if( findCase_Y_In_nY(character).length > 0 ) {
635 var flag = true
636 val tmpReply = findCase_Y_In_nY(character)
637 for( ex <- tmpReply ) {
638 if( localVN.contains(ex.toString) && FIRST_Group.contains(ex.toString) == true ) {
639 if( FIRST_Group(ex.toString).contains("ε") == false ) {
640 flag = false
641 }
642 }
643 else {
644 flag = false
645 }
646 if( flag == true ) {
647
648 if (FIRST_Group.contains(character.toString) == true) {
649 val tmp = "ε" + FIRST_Group(character.toString)
650 FIRST_Group(character.toString) = tmp.distinct
651 }
652 else {
653 FIRST_Group(character.toString) = "ε"
654 }
655 }
656 }
657 }
658 }
659 }
660 FIRST_Group
661 }
662
663 /*
664 * Function name: FOLLOW
665 * Function description: 根据dfsFOLLOW函数,获取各个非终结符的FOLLOW集元素
666 * Input parameters: -ArrayBuffer[ (String, String) ](产生式左右两部分分别构成元组的第1个和第2个元素)
667 * Return value: -Map[ String, String ](Map的key是非终结符,value是其FOLLOW集元素)
668 * Exception: 未处理
669 * Author: 来自高山
670 * Created date: Sat Oct 19 2019 +0800
671 * Editor: 来自高山
672 * Edited Date: Sat Oct 19 2019 +0800
673 */
674 def FOLLOW( string: ArrayBuffer[ (String, String) ] ): Map[ String, String ] = {
675 val localVN = VN
676 val FOLLOW_Group = Map[ String, String ]()
677 for( ch <- localVN ) {
678 FOLLOW_Group(ch.toString) = dfsFOLLOW(ch.toString)
679 }
680 FOLLOW_Group
681 }
682
683 /*
684 * Function name: dfsFOLLOW
685 * Function description: 使用深度优先搜索(DFS)寻找各个非终结符的FOLLOW集元素
686 * Input parameters: -String(指定的非终结符)
687 * Return value: -String(指定终结符的FOLLOW集元素)
688 * Exception: 未处理
689 * Author: 来自高山
690 * Created date: Sat Oct 19 2019 +0800
691 * Editor: 来自高山
692 * Edited Date: Sat Oct 19 2019 +0800
693 */
694 def dfsFOLLOW( ch: String ): String = {
695 val FOLLOWPositions = Map[ String, String ]()
696 val FOLLOW_Group = Map[ String, String ]()
697 val localLL1_G = LL1_G
698 val FIRST_Group = FIRST(localLL1_G)
699 val localVN = VN
700 for( ch <- localVN ) {
701 FOLLOWPositions(ch.toString) = findGivenValueFOLLOWPosition(ch.toString)
702 FOLLOW_Group(ch.toString) = "#"
703 }
704 var result = ""
705
706 if( FOLLOWPositions(ch).length == 4 ) {
707 if( FOLLOWPositions(ch)(1).toString == "T" ) {
708 result += FIRST_Group( FOLLOWPositions(ch)(0).toString )
709 FOLLOW_Group(ch) += result.distinct
710 }
711 else if( FOLLOWPositions(ch)(3).toString == "T" ) {
712 result += FIRST_Group( FOLLOWPositions(ch)(2).toString )
713 FOLLOW_Group(ch) += result.distinct
714 }
715 if( FOLLOWPositions(ch)(1).toString == "W" ) {
716 result += dfsFOLLOW( FOLLOWPositions(ch)(0).toString )
717 FOLLOW_Group(ch) = result.distinct
718 }
719 else if( FOLLOWPositions(ch)(3).toString == "W" ) {
720 result += dfsFOLLOW( FOLLOWPositions(ch)(2).toString )
721 FOLLOW_Group(ch) = result.distinct
722 }
723 }
724
725 if( FOLLOWPositions(ch).length == 2 ) {
726 if( FOLLOWPositions(ch)(1).toString == "T" ) {
727 result += FIRST_Group( FOLLOWPositions(ch)(0).toString )
728 FOLLOW_Group(ch) = result.distinct
729 }
730 else if( FOLLOWPositions(ch)(1).toString == "W" ) {
731 result += dfsFOLLOW( FOLLOWPositions(ch)(0).toString )
732 FOLLOW_Group(ch) = result.distinct
733 }
734 }
735 FOLLOW_Group(ch).replace("ε", "")
736 }
737
738 /*
739 * Function name: findGivenValueFOLLOWPosition
740 * Function description: 按照教材P79右上角的算法描述,求解构成每个非终结符的FOLLOW集的“依赖”(因为实现了这个函数,节省了我原先用循环叠加求解FOLLOW集的700+代码)
741 * Input parameters: -String(指定终结符)
742 * Return value: -String(指定终结符的FOLLOW集元素,无则为空)
743 * Exception: 未处理
744 * Author: 来自高山
745 * Created date: Sat Oct 19 2019 +0800
746 * Editor: 来自高山
747 * Edited Date: Sat Oct 19 2019 +0800
748 */
749 def findGivenValueFOLLOWPosition( ch: String ): String = {
750 var result = ""
751 val cnt = new ArrayBuffer[String]()
752 val localRelations = relations
753
754 for( ex <- localRelations ) {
755 if( ex._3 != "א" ) {
756 if( ex._2.contains(ch) ) {
757 // מ
758 if( ex._2.length == 3 ) {
759 // B A α B β
760 if( ex._2(1).toString == ch && judgeCase2( ex._1, ex._2(0).toString, ch, ex._2(2).toString ) ) {
761 val value = ex._2(2).toString + "T"
762 if( cnt.contains(value) == false ) {
763 cnt += value
764 result += value
765 }
766 }
767 // B A α B β
768 if( ex._2(1).toString == ch && judgeCase3( ex._1, ex._2(0).toString, ch, ex._2(2).toString ) ) {
769 val value = ex._1.toString + "W"
770 if( cnt.contains(value) == false ) {
771 cnt += value
772 result += value
773 }
774 }
775 }
776 if( ex._2.length == 2 ) {
777 // B A α B
778 if( ex._2(1).toString == ch && judgeCase3( ex._1, ex._2(0).toString, ch, "" ) ) {
779 val value = ex._1 + "W"
780 if( cnt.contains(value) == false ) {
781 cnt += value
782 result += value
783 }
784 }
785 }
786 }
787 if( ex._3.contains(ch) ) {
788 if( ex._3.length == 3 ) {
789 // B A α B β
790 if( ex._3(1).toString == ch && judgeCase2( ex._1, ex._3(0).toString, ch, ex._3(2).toString ) ) {
791 val value = ex._3(2).toString + "T"
792 if( cnt.contains(value) == false ) {
793 cnt += value
794 result += value
795 }
796 }
797 if( ex._3(1).toString == ch && judgeCase3( ex._1, ex._3(0).toString, ch, ex._3(2).toString ) ) {
798 val value = ex._1 + "W"
799 if( cnt.contains(value) == false ) {
800 cnt += value
801 result += value
802 }
803 }
804 }
805 if( ex._3.length == 2 ) {
806 // B A α B
807 if( ex._3(1).toString == ch && judgeCase3( ex._1, ex._3(0).toString, ch, "" ) ) {
808 val value = ex._1 + "W"
809 if( cnt.contains(value) == false ) {
810 cnt += value
811 result += value
812 }
813 }
814 }
815 }
816 }
817 else {
818 if( ex._2.contains(ch) ) {
819 if( ex._2.length == 3 ) {
820 // B A α B β
821 if( ex._2(1).toString == ch && judgeCase2( ex._1, ex._2(0).toString, ch, ex._2(2).toString ) ) {
822 val value = ex._2(2).toString + "T"
823 if( cnt.contains(value) == false ) {
824 cnt += value
825 result += value
826 }
827 }
828 if( ex._2(1).toString == ch && judgeCase3( ex._1, ex._2(0).toString, ch, ex._2(2).toString ) ) {
829 val value = ex._1 + "T"
830 if( cnt.contains(value) == false ) {
831 cnt += value
832 result += value
833 }
834 }
835 }
836 if( ex._2.length == 2 ) {
837 // B A α B
838 if( ex._2(1).toString == ch && judgeCase3( ex._1, ex._2(0).toString, ch, "" ) ) {
839 val value = ex._1 + "W"
840 if( cnt.contains(value) == false ) {
841 cnt += value
842 result += value
843 }
844 }
845 }
846 }
847 }
848 }
849 result
850 }
851
852 /*
853 * Function name: judgeCase2
854 * Function description: 按照教材P79右下角的算法描述,判断是否填充满足条件(2)的矩阵元素
855 * Input parameters: -String, String, String, String[分别代表条件(2)的四个字符]
856 * Return value: -Boolean(满足条件(2)则返回true,否则返回false)
857 * Exception: 未处理
858 * Author: 来自高山
859 * Created date: Tue Oct 15 2019 +0800
860 * Editor: 来自高山
861 * Edited Date: Tue Oct 15 2019 +0800
862 */
863 def judgeCase2( A: String, α: String, B: String, β: String ): Boolean = {
864 val localVN = VN
865 val wholeCharacters = allCharacters
866 val localLL1_G = LL1_G
867 val localFIRST = FIRST(localLL1_G)
868 if( localVN.contains(A) == true && wholeCharacters.contains(α) == true && localVN.contains(B) == true &&
869 wholeCharacters.contains(β) && localFIRST.contains(β) == true ) {
870 true
871 }
872 else {
873 false
874 }
875 }
876
877 /*
878 * Function name: judgeCase3
879 * Function description: 按照教材P79右下角的算法描述,判断是否填充满足条件(3)的矩阵元素
880 * Input parameters: -String, String, String, String[分别代表条件(3)的四个字符]
881 * Return value: -Boolean(满足条件(3)则返回true,否则返回false)
882 * Exception: 未处理
883 * Author: 来自高山
884 * Created date: Wed Oct 16 2019 +0800
885 * Editor: 来自高山
886 * Edited Date: Wed Oct 16 2019 +0800
887 */
888 def judgeCase3( A: String, α: String, B: String, β: String ): Boolean = {
889 val localVN = VN
890 val wholeCharacters = allCharacters
891 val localLL1_G = LL1_G
892 val localFIRST = FIRST(localLL1_G)
893 if( ( localVN.contains(A) == true && wholeCharacters.contains(α) == true && localVN.contains(B) == true ) ||
894 ( localVN.contains(A) == true && wholeCharacters.contains(α) == true && localVN.contains(B) == true && localFIRST(β).contains("ε") == true ) ) {
895 true
896 }
897 else {
898 false
899 }
900 }
901
902 /*
903 * Function name: initiateMatrix
904 * Function description: 初始化分析表(为了在控制台打印方便,表长为非终结符个数加一,表宽为终结符个数加一)
905 * Input parameters: 无
906 * Return value: -Array[ Array[ String] ](分析表矩阵元素构成的二维数组,除了第0行和第0列,其它列与行的元素均为null)
907 * Exception: 未处理
908 * Author: 来自高山
909 * Created date: Wed Oct 16 2019 +0800
910 * Editor: 来自高山
911 * Edited Date: Wed Oct 16 2019 +0800
912 */
913 def initiateMatrix(): Array[ Array[ String] ] = {
914 val localVN = VN
915 val localVT = VT
916 val result = Array.ofDim[String](localVN.length + 1, localVT.length + 1)
917 for( i <- 1 to localVN.length ) {
918 result(i)(0) = localVN(i - 1).toString
919 }
920 for( j <- 1 to localVT.length ) {
921 if( localVT(j - 1).toString == "ε" ) {
922 result(0)(j) = "#"
923 }
924 else {
925 result(0)(j) = localVT(j - 1).toString
926 }
927 }
928 result
929 }
930
931 /*
932 * Function name: createMatrix
933 * Function description: 按照教材P79右下角的算法描述,构造分析表
934 * Input parameters: 无
935 * Return value: -Array[ Array[String] ](分析表矩阵元素构成的二维数组)
936 * Exception: 未处理
937 * Author: 来自高山
938 * Created date: Wed Oct 16 2019 +0800
939 * Editor: 来自高山
940 * Edited Date: Wed Oct 16 2019 +0800
941 */
942 def createMatrix(): Array[ Array[String] ] = {
943 val result = initiateMatrix()
944 val localVT = VT
945 val localRelations = relations
946 val localLL1_G = LL1_G
947 val localFIRST = FIRST(localLL1_G)
948 val localFOLLOW = FOLLOW(localLL1_G)
949
950 for( ex <- localRelations ) {
951
952 if( ex._3 != "א" ) {
953 for( a <- localVT ) {
954 val ex2Length = ex._2.length
955 var range = ""
956 var α = ""
957 var flag = false
958 for( x <- 0 to (ex2Length - 1) ) {
959 if( localFIRST( ex._2(x).toString ).contains("ε") == false && flag == false ) {
960 α = ex._2(x).toString
961 range = localFIRST( α )
962 flag = true
963 }
964 }
965 if( range.contains(a) == true && flag == true ) {
966 result(getRow(ex._1))(getColumn(a.toString)) = ex._1 + "->" + ex._2
967 }
968 if( flag == false ) {
969 range = "ε"
970 result( getRow(ex._1) )( getColumn("ε") ) = ex._1 + "->" + "ε"
971 }
972
973 // case 3
974 if( range.contains("ε") == true && flag == false ) {
975 for( b <- localFOLLOW(α) ) {
976 result( getRow(ex._1.toString) )( getColumn(b.toString) ) = ex._1 + "->" + ex._2 // t --> tx
977 }
978 }
979
980 val ex3Length = ex._3.length
981 range = ""
982 flag = false
983 for( x <- 0 to (ex3Length - 1) ) {
984 if( localFIRST( ex._3(x).toString ).contains("ε") == false && flag == false ) {
985 α = ex._3(x).toString
986 range = localFIRST( α )
987 flag = true
988 }
989 }
990 if( range.contains(a) == true && flag == true ) {
991 result( getRow(ex._1) )( getColumn(a.toString) ) = ex._1 + "->" + ex._3
992 }
993 if( flag == false ) {
994 range = "ε"
995 result(getRow(ex._1))(getColumn("ε")) = ex._1 + "->" + "ε"
996 }
997
998 // case 3
999 if( range.contains("ε") == true && flag == false ) {
1000 for( b <- localFOLLOW(ex._1) ) {
1001 result( getRow(ex._1.toString) )( getColumn(b.toString) ) = ex._1 + "->" + ex._3 // t --> tx
1002 }
1003 }
1004 }
1005 }
1006
1007 else {
1008 for( a <- localVT ) {
1009 val ex2Length = ex._2.length
1010 var range = ""
1011 var α = ""
1012 var flag = false
1013 for( x <- 0 to (ex2Length - 1) ) {
1014 if( localFIRST( ex._2(x).toString ).contains("ε") == false && flag == false ) {
1015 α = ex._2(x).toString
1016 range = localFIRST(α)
1017 flag = true
1018 }
1019 }
1020 if( range.contains(a) == true && flag == true ) {
1021 result( getRow(ex._1) )( getColumn(a.toString) ) = ex._1 + "->" + ex._2
1022 }
1023 if( flag == false ) {
1024 range = "ε"
1025 result( getRow(ex._1) )( getColumn("ε") ) = ex._1 + "->" + "ε"
1026 }
1027
1028 // case 3
1029 if( range.contains("ε") == true && flag == false ) {
1030 for( b <- localFOLLOW(ex._1) ) {
1031 result( getRow(ex._1.toString) )( getColumn(b.toString) ) = ex._1 + "->" + ex._2
1032 }
1033 }
1034 }
1035 }
1036 }
1037 result
1038 }
1039
1040 /*
1041 * Function name: getRow
1042 * Function description: 获取指定字符在分析表中的行数
1043 * Input parameters: -String(指定字符)
1044 * Return value: -Int(指定字符所在的行数)
1045 * Exception: 未处理
1046 * Author: 来自高山
1047 * Created date: Wed Oct 16 2019 +0800
1048 * Editor: 来自高山
1049 * Edited Date: Wed Oct 16 2019 +0800
1050 */
1051 def getRow( ch: String ): Int = {
1052 val matrix = initiateMatrix()
1053 var result = -1
1054 if( ch == "α" ) {
1055 println( "1 --- getRow, ch == " + ch )
1056 }
1057 for( i <- 0 to (matrix.length - 1) ) {
1058 if( matrix(i)(0) == ch ) {
1059 result = i
1060 }
1061 }
1062 result
1063 }
1064
1065 /*
1066 * Function name: getColumn
1067 * Function description: 获取指定字符在分析表中的列数
1068 * Input parameters: -String(指定字符)
1069 * Return value: -Int(指定字符所在的列数)
1070 * Exception: 未处理
1071 * Author: 来自高山
1072 * Created date: Wed Oct 16 2019 +0800
1073 * Editor: 来自高山
1074 * Edited Date: Wed Oct 16 2019 +0800
1075 */
1076 def getColumn( ch: String ): Int = {
1077 val matrix = initiateMatrix()
1078 var result = -1
1079 for( i <- 0 to (matrix.length - 1) ) {
1080 for( j <- 0 to (matrix(i).length - 1) ) {
1081 if( matrix(0)(j) == ch ) {
1082 result = j
1083 }
1084 if( matrix(0)(j) == "#" && ch == "ε" ) {
1085 result = j
1086 }
1087 }
1088 }
1089 result
1090 }
1091
1092 /*
1093 * Function name: analyse
1094 * Function description: 对指定的字符串进行LL(1)分析
1095 * Input parameters: -String(输入的指定字符串)
1096 * Return value: -Boolean(分析成功则返回true,否则false)
1097 * Exception: 未处理(有出错提示)
1098 * Author: 来自高山
1099 * Created date: Wed Oct 16 2019 +0800
1100 * Editor: 来自高山
1101 * Edited Date: Wed Oct 16 2019 +0800
1102 */
1103 def analyse( expression: String ): Boolean = {
1104 val stack = new mutable.Stack[String]()
1105 var localExpression = expression
1106 val table = createMatrix()
1107 val localVT = VT
1108 val localVN = VN
1109 val localRelations = relations
1110
1111 stack.push("#")
1112 stack.push( localRelations(0)._1 )
1113
1114 var cnt = 0
1115 println( cnt + " " + " stack = " + stack + ", expression = " + localExpression + " initiate" )
1116
1117 while( stack.isEmpty == false ) {
1118 val stackTop = stack.top
1119 stack.pop()
1120 // 栈顶符号属于 非终结符
1121 if( localVN.contains(stackTop) == true ) {
1122 // 栈顶符号与表达式左端首字符 存在 关系
1123 if( table( getRow(stackTop) )( getColumn( localExpression(0).toString ) ) != null ) {
1124 val lastHalf = table( getRow(stackTop) )( getColumn( localExpression(0).toString ) ).split( "->", 2 ).last
1125 val length = lastHalf.length
1126 for( i <- 0 to (length - 1) ) {
1127 if( lastHalf != "ε" ) {
1128 stack.push(lastHalf(length - 1 - i).toString)
1129 }
1130 }
1131 cnt += 1
1132 println( cnt + " " + " stack = " + stack + ", expression = " + localExpression +
1133 ", analyse expression = " + table( getRow(stackTop) )( getColumn( localExpression(0).toString ) ) + ", POP, PUSH(" + lastHalf.reverse + ")")
1134 }
1135 // 栈顶符号与表达式左端首字符 不存在 关系
1136 else {
1137 // 栈顶符号 等于 表达式左端首字符
1138 if( stackTop == "#" && localExpression(0).toString == "#" ) {
1139 println("11111")
1140 return true
1141 }
1142 // 栈顶符号 不等于 表达式左端首字符
1143 else {
1144 println("1 - error")
1145 //stack.push( localExpression(0).toString )
1146 println( cnt + " " + " stack = " + stack + ", expression = " + localExpression )
1147 return false
1148 }
1149 }
1150 }
1151 // 栈顶符号属于 终结符
1152 if( localVT.contains(stackTop) == true ) {
1153 // 栈顶符号 等于 表达式左端首字符
1154 if( stackTop == localExpression(0).toString ) {
1155 if( stackTop == localExpression(0).toString ) {
1156 //stack.pop()
1157 localExpression = localExpression.drop(1)
1158 cnt += 1
1159 println( cnt + " " + " stack = " + stack + ", expression = " + localExpression + ", GETNEXT(" + stackTop + ")" )
1160 }
1161 // 栈顶符号 不等于 表达式左端首字符
1162 else {
1163 println("2 - error")
1164 return false
1165 }
1166 }
1167 }
1168 }
1169 true
1170 }
1171
1172 /*
1173 * Function name: judgeLeftRecursion
1174 * Function description: 判断是否存在形式上的左递归
1175 * Input parameters: -(String, String, String)(产生式的左端与右端的两个(或为1个)元素)
1176 * Return value: -Int(0表示无,1表示右端第1个元素存在形式上的左递归,2表示右端第2个元素)
1177 * Exception: 未处理
1178 * Author: 来自高山
1179 * Created date: Sat Oct 19 2019 +0800
1180 * Editor: 来自高山
1181 * Edited Date: Sat Oct 19 2019 +0800
1182 */
1183 def judgeLeftRecursion( expression: (String, String, String) ): Int = {
1184 var ans = 0 // ans = 0 means the current expression is not involved left-recursion
1185 if( expression._2.length >= 2 && expression._1 == expression._2(0).toString && expression._2.drop(1) != "ε" ) {
1186 ans += 1 // ans = 1 means the left recursion involves the expression._2
1187 }
1188 if( expression._3.length >= 2 && expression._1 == expression._3(0).toString && expression._3.drop(1) != "ε" ) {
1189 ans += 2 // ans = 2 means the left recursion involves the expression._3
1190 }
1191 ans // ans = 3 means the given expression is false since both exp(2) and exp(3) involved
1192 }
1193
1194 /*
1195 * Function name: eliminateLeftRecursion
1196 * Function description: 消除形式上的左递归
1197 * Input parameters: 无
1198 * Return value: -ArrayBuffer[ (String, String, String) ](消除左递归后的新文法)
1199 * Exception: 未处理
1200 * Author: 来自高山
1201 * Created date: Sat Oct 19 2019 +0800
1202 * Editor: 来自高山
1203 * Edited Date: Sat Oct 19 2019 +0800
1204 */
1205 def eliminateLeftRecursion(): ArrayBuffer[ (String, String, String) ] = {
1206 var localRelations = relations
1207 var invalidRelations = new ArrayBuffer[ (String, String, String) ]()
1208 val localCandidateLetters = allCandidateLetters
1209 val VN1 = "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩABCDEFGHIJKLMNOPQRSTUVWXYZ"
1210 val VT1 = "αβγδεζηθικλμνξοπρστυφχψωabcdefghijklmnopqrstuvwxyz"
1211 for( ex <- localRelations ) {
1212 if( ex._3 != "א" ) {
1213 if( judgeLeftRecursion( ex._1, ex._2, ex._3 ) == 1 ) {
1214 // P = ex._1, α = ex._2 - ex._1, β = ex._3, P' = newValue
1215 invalidRelations += ( ( ex._1, ex._2, ex._3 ) )
1216 val newValue = subString( usedCharacters, localCandidateLetters )(0)
1217 usedCharacters += newValue
1218 if( VN1.contains(newValue) && !VN.contains(newValue) ) {
1219 VN += newValue.toString
1220 allCharacters += newValue.toString
1221 }
1222 if( VT1.contains(newValue) && !VT.contains(newValue) ) {
1223 VT += newValue.toString
1224 allCharacters += newValue.toString
1225 }
1226 val α = ex._2.drop(1)
1227 val exp1 = ( ex._1, ex._3 + newValue.toString, "א" )
1228 val exp2 = ( newValue.toString, α.toString + newValue.toString, "ε" )
1229 // println( "1 -- exp1._1 = " + exp1._1 + ", exp1._2 = " + exp1._2 + ", exp1._3 = " + exp1._3 )
1230 // println( "1 -- exp2._1 = " + exp2._1 + ", exp2._2 = " + exp2._2 + ", exp2._3 = " + exp2._3 )
1231 localRelations += exp1
1232 localRelations += exp2
1233 }
1234 else if( judgeLeftRecursion( ex._1, ex._2, ex._3 ) == 2 ) {
1235 // P = ex._1, α = ex._3 - ex._1, β = ex._3, P' = newValue
1236 invalidRelations += ( ( ex._1, ex._2, ex._3 ) )
1237 val newValue = subString( usedCharacters, localCandidateLetters )(0)
1238 if( VN1.contains(newValue) && !VN.contains(newValue) ) {
1239 VN += newValue.toString
1240 allCharacters += newValue.toString
1241 }
1242 if( VT1.contains(newValue) && !VT.contains(newValue) ) {
1243 VT += newValue.toString
1244 allCharacters += newValue.toString
1245 }
1246 usedCharacters += newValue
1247 val α = ex._3.drop(1)
1248 val exp1 = ( ex._1, ex._3 + newValue.toString, "א" )
1249 val exp2 = ( newValue.toString, α.toString + newValue.toString, "ε" )
1250 // println( "2 -- exp1._1 = " + exp1._1 + ", exp1._2 = " + exp1._2 + ", exp1._3 = " + exp1._3 )
1251 // println( "2 -- exp2._1 = " + exp2._1 + ", exp2._2 = " + exp2._2 + ", exp2._3 = " + exp2._3 )
1252 localRelations += exp1
1253 localRelations += exp2
1254 }
1255 else if( judgeLeftRecursion( ex._1, ex._2, ex._3 ) == 3 ){
1256 println( "error in the function eliminateLeftRecursion" )
1257 }
1258 }
1259 else {
1260 if( judgeLeftRecursion( ex._1, ex._2, ex._3 ) == 1 ) {
1261 // P = ex._1, α = ex._2 - ex._1, β = ex._3, P' = newValue
1262 invalidRelations += ( ( ex._1, ex._2, ex._3 ) )
1263 val newValue = subString( usedCharacters, localCandidateLetters )(0)
1264 if( VN1.contains(newValue) && !VN.contains(newValue) ) {
1265 VN += newValue.toString
1266 allCharacters += newValue.toString
1267 }
1268 if( VT1.contains(newValue) && !VT.contains(newValue) ) {
1269 VT += newValue.toString
1270 allCharacters += newValue.toString
1271 }
1272 usedCharacters += newValue
1273 val α = ex._2.drop(1)
1274 val exp1 = ( ex._1, newValue.toString, "א" )
1275 val exp2 = ( newValue.toString, α.toString + newValue.toString, "ε" )
1276 // println( "3 -- exp1._1 = " + exp1._1 + ", exp1._2 = " + exp1._2 + ", exp1._3 = " + exp1._3 )
1277 // println( "3 -- exp2._1 = " + exp2._1 + ", exp2._2 = " + exp2._2 + ", exp2._3 = " + exp2._3 )
1278 localRelations += exp1
1279 localRelations += exp2
1280 }
1281 }
1282 }
1283 for( ex <- invalidRelations ) {
1284 localRelations = localRelations.-(ex)
1285 }
1286 relations = localRelations
1287 localRelations
1288 }
1289
1290 /*
1291 * Function name: subString
1292 * Function description: 获取两输入字符串的差集(要求两者均非空)
1293 * Input parameters: 无
1294 * Return value: -String(两输入字符串的差集)
1295 * Exception: 未处理
1296 * Author: 来自高山
1297 * Created date: Sat Oct 19 2019 +0800
1298 * Editor: 来自高山
1299 * Edited Date: Sat Oct 19 2019 +0800
1300 */
1301 def subString( usedCharacters: String, localCandidateLetters: String ): String = {
1302 require( usedCharacters.length != 0 && localCandidateLetters.length != 0 )
1303 var ans = ""
1304 var A = usedCharacters
1305 var B = localCandidateLetters
1306 if( A.length < B.length ) {
1307 val tmp = A
1308 A = B
1309 B = tmp
1310 }
1311 for( i <- 0 to (A.length - 1) ) {
1312 var j = 0
1313 while( j < B.length && B(j) != A(i) ) {
1314 j += 1
1315 }
1316 if( j == B.length ) {
1317 ans += A(i)
1318 }
1319 }
1320 ans
1321 }
1322 }
含GUI的代码:
LL1_try_GUI object类(Scala):
1 import java.awt.{BorderLayout, Color}
2 import java.awt.event.{ActionEvent, ActionListener}
3 import java.io.FileInputStream
4
5 import javax.swing.table.{AbstractTableModel, DefaultTableCellRenderer, DefaultTableColumnModel, DefaultTableModel, TableColumn, TableModel}
6 import javax.swing.{JButton, JFileChooser, JFrame, JPanel, JScrollPane, JTable, JTextField, JTextPane}
7 import pojo.Analyse
8
9 import scala.collection.mutable
10 import scala.collection.mutable.{ArrayBuffer, Map}
11 import scala.util.matching.Regex
12
13
14 object LL1_try_GUI {
15 private final var allCharacters = new String()
16 private final var relations = new ArrayBuffer[ (String, String, String) ]()
17 private final var VN = new String()
18 private final var VT = new String()
19 private val allCandidateLetters = "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩABCDEFGHIJKLMNOPQRSTUVWXYZ"
20 private final var usedCharacters = ""
21
22
23 private var LL1_G = new ArrayBuffer[ (String, String) ]()//ArrayBuffer( ("E", "TG"), ("G", "+TG|-TG"), ("G", "ε"), ("T", "FS"), ("S", "*FS|/FS"),
24 //("S", "ε"), ("F", "(E)"), ("F", "i") )//, ("Y", "*FS|/FS"), ("Y", "+TG|-TG"), ("Y", "x"), ("Y", "M"), ("M", "i"), ("M", "ε") )
25 // test data 1:
26 // ( ("E", "TG"), ("G", "+TG|-TG"), ("G", "ε"), ("T", "FS"), ("S", "*FS|/FS"),
27 // ("S", "ε"), ("F", "(E)"), ("F", "i"), ("Y", "S"), ("Y", "Gx"), ("Y", "x"), ("Y", "M"), ("M", "i"), ("M", "ε") )
28 // test data 2:
29 // ( ("D", "*FD"), ("D", "ε"), ("T", "FD"), ("E", "TC"), ("F", "(E)"), ("F", "i"), ("C", "+TC"), ("C", "ε") )
30 // test data 3:
31 // ( ("E", "E+T|T"), ("T", "T*F|T"), ("F", "(E)|i") )
32 // stand test data:
33 // ( ("E", "TG"), ("G", "+TG|-TG"), ("G", "ε"), ("T", "FS"), ("S", "*FS|/FS"), ("S", "ε"), ("F", "(E)"), ("F", "i") )
34
35 val staticAnalyseList : ArrayBuffer[Analyse] = new ArrayBuffer[Analyse]();
36 var staticTestMatrix : Array[ Array[String] ] = new Array[Array[String]](0)
37 var staticStringBuilder : StringBuilder = new StringBuilder();
38 var staticStringBuilder2 : StringBuilder = new StringBuilder();
39
40 def main(args: Array[String]): Unit = {
41 GUI1
42 }
43
44 /*
45 * Function name: displayStack
46 * Function description: 输出栈的所有元素
47 * Input parameters: -mutable.Stack[String](待处理的String类型的栈)
48 * Return value: -String(栈所有元素组成的字符串)
49 * Exception: 未处理
50 * Author: 来自高山
51 * Created date: Mon Oct 21 2019 +0800
52 * Editor: 来自高山
53 * Edited Date: Mon Oct 21 2019 +0800
54 */
55 def displayStack( stack: mutable.Stack[String] ): String = {
56 var result = ""
57 for( ex <- stack ) {
58 result += ex
59 }
60 result
61 }
62
63 /*
64 * Function name: utility
65 * Function description: 辅助输出函数
66 * Input parameters: 无
67 * Return value: 无
68 * Exception: 未处理
69 * Author: 来自高山
70 * Created date: Sun Oct 20 2019 +0800
71 * Editor: 来自高山
72 * Edited Date: Sun Oct 20 2019 +0800
73 */
74 def utility(): Unit = {
75 staticStringBuilder.append("VT = " + VT +"\r\n");
76 staticStringBuilder.append("VN = " + VN +"\r\n");
77 staticStringBuilder.append( "allCharacters = " + allCharacters +"\r\n");
78 val tx = FIRST(LL1_G)
79 staticStringBuilder.append( "FIRST集: " +"\r\n");
80 for( t <- tx ) {
81 if( allCharacters.contains( t._1 ) ) {
82 staticStringBuilder.append( "FIRST("+ t._1 + ") = {" + t._2.mkString(",") + "}\r\n");
83 }
84 }
85 val ex = FOLLOW(LL1_G)
86 staticStringBuilder.append("FOLLOW集: "+"\r\n");
87 for( t <- ex ) {
88 if( VN.contains( t._1 ) ) {
89 staticStringBuilder.append( "FOLLOW("+ t._1 + ") = {" + t._2.mkString(",") + "}\r\n");
90 }
91 }
92 val testMatrix1 = createMatrix()
93 staticTestMatrix = testMatrix1;
94 for( ex <- LL1_G ) {
95 staticStringBuilder2.append( ex._1 + "->" + ex._2 + "\r\n")
96 }
97 }
98
99 /*
100 * Function name: GUI1
101 * Function description: 实现图形化界面展示,开始界面
102 * Input parameters: 无
103 * Return value: 无
104 * Exception: 未处理
105 * Author: 来自高山
106 * Created date: Sun Oct 20 2019 +080
107 * Editor: 来自高山
108 * Edited Date: Sun Oct 20 2019 +0800
109 */
110 def GUI1(): Unit = {
111 val jFrame = new JFrame("LL(1)文法分析");
112 val jPanel = new JPanel();
113 jFrame.setBounds( 0, 10,1000,90);
114
115 val appendFileJButton2 = new JButton("开始分析");
116 appendFileJButton2.setBounds( 100, 400,200,30);
117 appendFileJButton2.addActionListener(new ActionListener {
118 override def actionPerformed(e: ActionEvent): Unit = {
119 GUI2
120 jFrame.dispose()
121 }
122 })
123
124 //添加文件按钮
125 val appendFileJButton = new JButton("添加文件");
126 appendFileJButton.setBounds( 300, 400,200,30);
127 appendFileJButton.addActionListener(new ActionListener {
128 override def actionPerformed(e: ActionEvent): Unit = {
129 val fileChooser = new JFileChooser();
130 fileChooser.showOpenDialog(jFrame);
131 val filePath = fileChooser.getSelectedFile.getAbsolutePath
132 initiate(filePath)
133 utility
134 }
135 })
136 val appendFileJButton3 = new JButton("退出程序")
137 appendFileJButton3.setBounds(500, 400, 200, 30)
138 appendFileJButton3.addActionListener(new ActionListener {
139 override def actionPerformed(e: ActionEvent): Unit = {
140 jFrame.dispose()
141 }
142 })
143
144 jPanel.add(appendFileJButton)
145 jPanel.add(appendFileJButton2)
146 jPanel.add(appendFileJButton3)
147 jPanel.setBackground(Color.gray)
148 jFrame.add(jPanel)
149 import java.awt.FlowLayout
150 jPanel.setLayout(new FlowLayout(FlowLayout.LEADING, 200, 20))
151 jFrame.setResizable(false);
152 jFrame.setVisible(true);
153 }
154
155 /*
156 * Function name: GUI2
157 * Function description: 实现图形化界面展示,分析界面
158 * Input parameters: 无
159 * Return value: 无
160 * Exception: 未处理
161 * Author: 菊花侠
162 * Created date: Sat Oct 19 2019 +0800
163 * Editor: 来自高山
164 * Edited Date: Sun Oct 20 2019 +0800
165 */
166 def GUI2(): Unit = {
167 val jFrame = new JFrame("LL(1)文法分析");
168 jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
169 jFrame.setResizable(false)
170 jFrame.setBounds(0,0,1000,810);
171 jFrame.setLayout(null)
172
173 //输入行
174 val inputJPanel = new JPanel();
175 inputJPanel.setBounds(0,0,1000,30);
176 inputJPanel.setLayout(null);
177
178 val inputJTextField = new JTextField();
179 inputJTextField.setBounds(0,0,300,30);
180 // inputJTextField.setText("i+i*i*i#");
181 // inputJTextField.setPreferredSize(new Dimension(300,30));
182 val inputJButton = new JButton("确认");
183 inputJButton.setBounds(320,0,60,30);
184 // inputJButton.setPreferredSize(new Dimension(30,30));
185 inputJPanel.add(inputJTextField)
186 inputJPanel.add(inputJButton)
187 jFrame.add(inputJPanel);
188
189
190 val displayFileJTextPane = new JTextPane();
191 displayFileJTextPane.setEditable(false);
192
193 val displayFileJScrollPane = new JScrollPane();
194 displayFileJScrollPane.setBounds(0,64,1000,300);
195 displayFileJScrollPane.setViewportView(displayFileJTextPane);
196 jFrame.add(displayFileJScrollPane)
197
198 //添加文件按钮
199 // val appendFileJButton = new JButton("添加文件");
200 val appendFileJButton = new JButton("显示当前文法")
201 appendFileJButton.setBounds(0, 32,120,30)
202 appendFileJButton.addActionListener(new ActionListener {
203 override def actionPerformed(e: ActionEvent): Unit = {
204 displayFileJTextPane.setText(staticStringBuilder2.toString());
205 }
206 })
207
208 val appendFileJButton2 = new JButton("返回")
209 appendFileJButton2.setBounds(220, 32, 120, 30)
210 appendFileJButton2.addActionListener(new ActionListener {
211 override def actionPerformed(e: ActionEvent): Unit = {
212 GUI1
213 jFrame.dispose()
214 }
215 })
216
217 val appendFileJButton3 = new JButton("退出")
218 appendFileJButton3.setBounds(440, 32, 120, 30)
219 appendFileJButton3.addActionListener(new ActionListener {
220 override def actionPerformed(e: ActionEvent): Unit = {
221 jFrame.dispose()
222 }
223 })
224
225 jFrame.add(appendFileJButton)
226 jFrame.add(appendFileJButton2)
227 jFrame.add(appendFileJButton3)
228
229 val dataMode1 = new AbstractTableModel() {
230
231 override def getColumnCount = 5
232
233 override
234
235 def getRowCount = staticAnalyseList.length
236 override
237 def getValueAt(row: Int, col: Int): String = {
238 val a = staticAnalyseList(row);
239 if(col == 0){
240 return a.getStep();
241 }
242 if(col == 1){
243 return a.getAnalysisStack;
244 }
245 if(col == 2){
246 return a.getRemainingString;
247 }
248 if(col == 3){
249 return a.getProductionType;
250 }
251 if(col == 4){
252 return a.getAction;
253 }
254 return new String();
255 }
256 }
257
258 val table1JScrollPane = new JScrollPane();
259 val table1JTable = new JTable(dataMode1);
260 table1JScrollPane.setBounds(0,370,690,300)
261 // table1JTable.setBounds(0,170,500,300);
262 table1JScrollPane.setViewportView(table1JTable);
263 val table1JTextPaneScrollPan = new JScrollPane();
264 table1JTextPaneScrollPan.setBounds(692,370,300,300);
265 val table1JTextPane = new JTextPane();
266 table1JTextPane.setEditable(false);
267 table1JTextPaneScrollPan.setViewportView(table1JTextPane);
268 jFrame.add(table1JTextPaneScrollPan);
269 jFrame.add(table1JScrollPane);
270
271 val table2JScrollPane = new JScrollPane();
272 table2JScrollPane.setBounds(0,682,300,300)
273 // table2JScrollPane.setBounds(0,482);
274
275 val table2JTable = new JTable();
276 table2JTable.setBounds(0,682,1000,300);
277 val r = new DefaultTableCellRenderer();
278 r.setHorizontalAlignment(0)
279 table2JTable.setDefaultRenderer(classOf[Any],r);
280 table2JScrollPane.add(table2JTable)
281 jFrame.add(table2JTable);
282
283 jFrame.setVisible(true);
284
285 inputJButton.addActionListener(new ActionListener {
286 override def actionPerformed(e: ActionEvent): Unit = {
287 staticAnalyseList.clear();
288 // staticTestMatrix : Array[ Array[String] ] = new Array[Array[String]](0)
289 staticTestMatrix = createMatrix();
290 analyse( inputJTextField.getText() + "#" );
291 val dataMode1 = new AbstractTableModel() {
292
293 override def getColumnCount = 5
294
295 override
296
297 def getRowCount = staticAnalyseList.length
298 override
299 def getValueAt(row: Int, col: Int): String = {
300 val a = staticAnalyseList(row);
301 if(col == 0){
302 return a.getStep();
303 }
304 if(col == 1){
305 return a.getAnalysisStack;
306 }
307 if(col == 2){
308 return a.getRemainingString;
309 }
310 if(col == 3){
311 return a.getProductionType;
312 }
313 if(col == 4){
314 return a.getAction;
315 }
316 return new String();
317 }
318
319 }
320 table1JTable.setModel(dataMode1);
321
322 val dataMode2 = new AbstractTableModel() {
323
324 override def getColumnCount = 9
325
326 override
327
328 def getRowCount = staticTestMatrix.length
329 override
330 def getValueAt(row: Int, col: Int) = staticTestMatrix(row)(col)
331 }
332 table2JTable.setModel(dataMode2);
333 table1JTextPane.setText(staticStringBuilder.toString())
334 }
335 })
336 }
337
338 /*
339 * Function name: initiate
340 * Function description: 初始化全局变量
341 * Input parameters: the absolute path of the language-rule source file
342 * Return value: 无
343 * Exception: 未处理
344 * Author: 来自高山
345 * Created date: Sat Oct 19 2019 +0800
346 * Editor: 来自高山
347 * Edited Date: Sat Oct 19 2019 +0800
348 */
349 def initiate( filePath: String ): Unit = {
350 LL1_G = parseFile(filePath)
351 allCharacters = getWholeCharacters(LL1_G)
352 usedCharacters = allCharacters
353 relations = getRelation(LL1_G)
354 VN = getVN(allCharacters)
355 VT = getVT(allCharacters)
356 eliminateLeftRecursion // eliminate all the left recursion at first
357 }
358
359 /*
360 * Function name: displayRelations
361 * Function description: display all he language rules
362 * Input parameters: 无
363 * Return value: 无
364 * Exception: 未处理
365 * Author: 来自高山
366 * Created date: Sat Oct 19 2019 +0800
367 * Editor: 来自高山
368 * Edited Date: Sat Oct 19 2019 +0800
369 */
370 def displayRelations(): Unit = {
371 for( ex <- relations ) {
372 if( ex._3 != "א" ) {
373 println( ex._1 + "->" + ex._2 + "|" + ex._3 )
374 }
375 else {
376 println( ex._1 + "->" + ex._2 )
377 }
378 }
379 }
380
381 /*
382 * Function name: parseFile
383 * Function description: 解析文本文件,保存在数组中
384 * Input parameters: 文本绝对路径
385 * Return value: -ArrayBuffer[ ( String, String ) ](String类型的元组ArrayBuffer数组)
386 * Exception: 未处理
387 * Author: 来自高山
388 * Created date: Fri Oct 18 2019 +0800
389 * Editor: 来自高山
390 * Edited Date: Fri Oct 18 2019 +0800
391 */
392 def parseFile( filePath: String ): ArrayBuffer[ ( String, String ) ] = {
393 val result = new ArrayBuffer[ ( String, String ) ]( countLines( readFromTxtByLine(filePath) ) )
394 val sourceFile = readFromTxtByLine(filePath) //filePath
395 for( line <- sourceFile ) {
396 val tmp = line.split( "->", 2 )
397 result += ( ( tmp.head, tmp.last ) )
398 }
399 result
400 }
401
402 /*
403 * Function name: countLines
404 * Function description: 计算文本行数,用于创建接收数组时开辟相应空间
405 * Input parameters: -Array[String](文本文件数据构成的数组)
406 * Return value: -Int(文本行数)
407 * Exception: 未处理
408 * Author: 来自高山
409 * Created date: Fri Oct 18 2019 +0800
410 * Editor: 来自高山
411 * Edited Date: Sat Oct 19 2019 +0800
412 */
413 def countLines( sourceFile: Array[String] ): Int = {
414 var cnt = 0
415 for( line <- sourceFile ) {
416 cnt += 1
417 }
418 cnt
419 }
420
421 /*
422 * Function name: readFromTxtByLine
423 * Function description: 读取文本文件
424 * Input parameters: -String(文本文件绝对路径)
425 * Return value: -Array[String](文本文件构成的数组,每行数据占一个数组元素)
426 * Exception: -未处理
427 * Author: 来自高山
428 * Created date: Fri Oct 18 2019 +0800
429 * Editor: 来自高山
430 * Edited Date: Fri Oct 18 2019 +0800
431 */
432 def readFromTxtByLine(filePath: String): Array[String] = {
433 import scala.io.Source
434 val source = Source.fromFile(filePath, "UTF-8")
435 //val lineIterator = source.getLines()
436 //lineIterator.foreach()
437 val lines = source.getLines().toArray
438 source.close()
439 //println(lines.size)
440 lines
441 }
442
443 /*
444 * Function name: getWholeCharacters
445 * Function description: 获取文法的除“|”之外的所有字符
446 * Input parameters: -ArrayBuffer[ (String, String) ](由文法左右两部分字符构成一个元组的数组,筛掉“|”)
447 * Return value: -String(文法的除“|”之外的所有字符)
448 * Exception: 未处理(有出错提示)
449 * Author: 来自高山
450 * Created date: Fri Oct 11 2019 +0800
451 * Editor: 来自高山
452 * Edited Date: Fri Oct 11 2019 +0800
453 */
454 def getWholeCharacters( string: ArrayBuffer[ (String, String) ] ): String = {
455 var wholeCharacters = ""
456 for( expression <- string ) {
457 wholeCharacters += expression._1 + expression._2
458 }
459 val pattern = new Regex("\\|")
460 val result = pattern replaceAllIn( wholeCharacters, "" )
461 if( result.isEmpty )
462 "function getWholeCharacters failed"
463 else
464 result.distinct
465 }
466 /*
467 * Function name: getVN
468 * Function description: 获取文法的所有非终结符(non-terminal character),默认大写字母为非终结符,使用正则表达式匹配
469 * Input parameters: -String(函数getWholeCharacters传来的文法的所有字符)
470 * Return value: -String(文法的所有非终结符)
471 * Exception: 未处理(有出错提示)
472 * Author: 来自高山
473 * Created date: Fri Oct 11 2019 +0800
474 * Editor: 来自高山
475 * Edited Date: Fri Oct 11 2019 +0800
476 */
477 def getVN( string: String ): String = {
478 //match big letter:
479 //^[A-Z]+$
480 val pattern = new Regex("[A-Z]")//("^[A-Z]+$")
481 if( (pattern findAllIn string) != null )
482 (pattern findAllIn string).mkString("")
483 else
484 "function getVN failed"
485 }
486
487 /*
488 * Function name: getVT
489 * Function description: 获取文法的所有非终结符(terminal character),默认大写字母外的字符为终结符,使用正则表达式匹配
490 * Input parameters: -String(函数getWholeCharacters传来的文法的所有字符)
491 * Return value: -String(文法的所有终结符)
492 * Exception: 未处理(有出错提示)
493 * Author: 来自高山
494 * Created date: Fri Oct 11 2019 +0800
495 * Editor: 来自高山
496 * Edited Date: Fri Oct 11 2019 +0800
497 */
498 def getVT( string: String ): String = {
499 val pattern1 = new Regex("[A-Z]")
500 val pattern2 = new Regex("\\|")
501 val firstFilter = pattern1 replaceAllIn( string, "" )
502 val result = pattern2 replaceAllIn( firstFilter, "" )
503 if( result.isEmpty == false )
504 result
505 else
506 return "function getVT failed"
507 }
508 /*
509 * Function name: getRelation
510 * Function description: 获取文法每一行对应的推导关系,若文法只推出了1项(即没有符号“|”),则返回元组的第三个用希伯来字母“א”示空
511 * Input parameters: -ArrayBuffer[ (String, String)(已经分割好的文法左右部分构成的数组)
512 * Return value: -ArrayBuffer[ (String, String, String) ](元组第一个元素为推导式左边符号,第二为右边第二个符号串,第三为右边(若有)第三个符号串)
513 * Exception: 未处理
514 * Author: 来自高山
515 * Created date: Fri Oct 11 2019 +0800
516 * Editor: 来自高山
517 * Edited Date: Fri Oct 11 2019 +0800
518 */
519 def getRelation( string: ArrayBuffer[ (String, String) ] ): ArrayBuffer[ (String, String, String) ] = {
520 val relation = new ArrayBuffer[ (String, String, String) ]()
521 for( expression <- string ) {
522 if( expression._2.contains("|") == false ) {
523 relation += ( ( expression._1, expression._2, "א" ) )
524 }
525 else {
526 val tmp = expression._2.split("\\|", 2 )
527 relation += ( ( expression._1, tmp.head, tmp.last ) )
528 }
529 }
530 relation
531 }
532
533 /*
534 * Function name: findFirst
535 * Function description: 获取指定字符的右边两个(可能是一个)导出字符串的首个非 ε 组成的字符串
536 * Input parameters: -String(指定字符)
537 * Return value: -String(指定字符的右边两个(可能是一个)导出字符串的首个非 ε 组成的字符串)
538 * Exception: 未处理
539 * Author: 来自高山
540 * Created date: Fri Oct 11 2019 +0800
541 * Editor: 来自高山
542 * Edited Date: Fri Oct 11 2019 +0800
543 */
544 def findFirst( ch: String ): String = {
545
546 val localRelations = relations
547 var result = ""
548 for( ex <- localRelations ) {
549 if( ch == ex._1 ) {
550 if( ex._3 != "א" ) {
551 if( VT.contains( ex._2(0) ) && ex._2(0) != 'ε' ) {
552 result += ex._2(0).toString
553 }
554 if( VT.contains( ex._3(0) ) && ex._3(0) != 'ε' ) {
555 result += ex._3(0).toString
556 }
557 }
558 else {
559 if( VT.contains( ex._2(0) ) && ex._2(0) != 'ε' ) {
560 result += ex._2(0).toString
561 }
562 }
563 }
564 }
565 result
566 }
567
568 /*
569 * Function name: judgeOnlyOneVoidSuccession
570 * Function description: 判断指定字符是否可推出唯一的字符ε
571 * Input parameters: -String(指定字符串)
572 * Return value: -Boolean(存在则true,否则false)
573 * Exception: 未处理
574 * Author: 来自高山
575 * Created date: Fri Oct 11 2019 +0800
576 * Editor: 来自高山
577 * Edited Date: Fri Oct 11 2019 +0800
578 */
579 def judgeOnlyOneVoidSuccession( ch: String ): Boolean = {
580 val localRelations = relations
581 var result = 1
582 for( ex <- localRelations ) {
583 if( ch == ex._1 ) {
584 if( ex._3 != "א" ) {
585 if( ( ex._2.length == 1 && ex._2(0) == 'ε' ) || (ex._3.length == 1 && ex._3(0) == 'ε') ) {
586 result = 1
587 }
588 else {
589 result = 0
590 }
591 }
592 else {
593 if( ( ex._2.length == 1 && ex._2(0) == 'ε' ) ) {
594 result = 1
595 }
596 else {
597 result = 0
598 }
599 }
600 }
601 }
602 if( result == 1 ) true else false
603 }
604
605 /*
606 * Function name: judgeCaseXY
607 * Function description: 判断构造FIRST集时可能的第3种情况的(1),即若X->Y...是一个产生式且Y∈VN(省略若干描述)
608 * Input parameters: -Char(指定字符,即可能满足条件的产生式的左边字符)
609 * Return value: -Boolean(满足则true,否则false)
610 * Exception: 未处理
611 * Author: 来自高山
612 * Created date: Sat Oct 12 2019 +0800
613 * Editor: 来自高山
614 * Edited Date: Sat Oct 12 2019 +0800
615 */
616 def judgeCaseXY( ch: Char ): Boolean = {
617 val localVN = VN
618 val localRelations = relations
619 var result = 0
620 if( localVN.contains(ch) == true ) {
621 for( ex <- localRelations ) {
622 if( ex._1(0) == ch ) {
623 if( localVN.contains( ex._2(0) ) || localVN.contains( ex._3(0) ) ) {
624 result += 1
625 }
626 }
627 }
628 }
629 if( result > 0 )
630 true
631 else
632 false
633 }
634
635 /*
636 * Function name: findCase_Y_In_XY
637 * Function description: 获取构造FIRST集时可能的第3种情况的(1),即若X->Y...是一个产生式且Y∈VN(省略若干描述)时的Y
638 * Input parameters: -Char(指定字符,即可能满足条件的产生式的左边字符)
639 * Return value: -String(Y构成的String字符串,无则为空)
640 * Exception: 未处理
641 * Author: 来自高山
642 * Created date: Sat Oct 12 2019 +0800
643 * Editor: 来自高山
644 * Edited Date: Sat Oct 12 2019 +0800
645 */
646 def findCase_Y_In_XY( ch: Char ): String = {
647 val localVN = VN
648 val localRelations = relations
649 var result = ""
650 if( localVN.contains(ch) == true ) {
651 for( ex <- localRelations ) {
652 if( ex._1(0) == ch ) {
653 if( ex._3 != "א" ) {
654 if( localVN.contains( ex._2(0) ) == true ) {
655 result += ex._2(0).toString
656 }
657 if( localVN.contains( ex._3(0) ) == true ) {
658 result += ex._3(0).toString
659 }
660 }
661 else {
662 if( localVN.contains( ex._2(0) ) == true ) {
663 result += ex._2(0).toString
664 }
665 }
666 }
667 }
668 }
669 result
670 }
671
672 /*
673 * Function name: findCase_Y_In_nY
674 * Function description: 获取构造FIRST集时可能的第3种情况的(2)时的FIRST(Yi)中所有的非ε-元素(省略描述若干字)
675 * Input parameters: -Char(指定字符,即可能满足条件的产生式的左边字符)
676 * Return value: -String(FIRST(Yi)中所有的非ε-元素构成的String字符串,无则为空)
677 * Exception: 未处理
678 * Author: 来自高山
679 * Created date: Sat Oct 12 2019 +0800
680 * Editor: 来自高山
681 * Edited Date: Sat Oct 12 2019 +0800
682 */
683 def findCase_Y_In_nY( ch: Char ): String = {
684 val localVN = VN
685 val localRelations = relations
686 var result = ""
687 for( ex <- localRelations ) {
688 if (ex._1 == ch.toString) {
689 var tmp = ""
690
691 if (ex._3 != 'א') {
692 var cnt = 0
693 for (tx <- ex._2) {
694 // add the element belongs to tmp
695 if (localVN.contains(tx)) {
696 tmp += tx.toString
697 cnt += 1
698 }
699 // otherwise, reset tmp as empty string
700 else {
701 tmp = ""
702 }
703 }
704 if (cnt == ex._2.length) {
705 result += tmp
706 }
707
708 // reset
709 cnt = 0
710 tmp = ""
711 for (tx <- ex._3) {
712 // add the element belongs to tmp
713 if (localVN.contains(tx)) {
714 tmp += tx.toString
715 cnt += 1
716 }
717 // otherwise, reset result as empty string
718 else {
719 tmp = ""
720 }
721 }
722 if (cnt == ex._3.length) {
723 result += tmp
724 }
725 }
726 else {
727 tmp = ""
728 var cnt = 0
729 for (tx <- ex._2) {
730 // add the element belongs to tmp
731 if (localVN.contains(tx)) {
732 tmp += tx.toString
733 cnt += 1
734 }
735 // otherwise, reset tmp as empty string
736 else {
737 tmp = ""
738 }
739 }
740 if (cnt == ex._2.length) {
741 result += tmp
742 }
743 }
744 }
745 }
746 result = result.distinct
747 result
748 }
749
750 /*
751 * Function name: FIRST
752 * Function description: 按照教材P78左下角的算法描述实现求解指定文法FIRST集;因用的是循环迭代求解,因此代码较长
753 * Input parameters: -ArrayBuffer[ (String, String) ](产生式左右两部分分别构成元组的第1个和第2个元素)
754 * Return value: -Map[ String, String ](Map的key是非终结符,value是其FIRST元素)
755 * Exception: 未处理
756 * Author: 来自高山
757 * Created date: Mon Oct 14 2019 +0800
758 * Editor: 来自高山
759 * Edited Date: Sat Oct 19 2019 +0800
760 */
761 def FIRST( string: ArrayBuffer[ (String, String) ] ): Map[ String, String ] = {
762 val FIRST_Group = Map[ String, String ]()
763
764 val wholeCharacters = allCharacters
765 val localVT = VT
766 val localVN = VN
767
768 for( character <- wholeCharacters ) {
769 // case 1
770 if( localVT.contains(character) ) {
771 //if there exist the original key that equals the current one
772 if( FIRST_Group.contains(character.toString) == true ) {
773 val tmp = character.toString + FIRST_Group(character.toString)
774 FIRST_Group(character.toString) = tmp.distinct
775 }
776 //otherwise
777 else {
778 FIRST_Group(character.toString) = character.toString
779 }
780 }
781
782 // case 2
783 if( localVN.contains(character.toString) == true ) {
784 // case 2.1
785 val value = findFirst(character.toString)
786 if ( value.length != 0 ) {
787 if ( FIRST_Group.contains(character.toString) == true ) {
788 for( ch <- value ) {
789 val tmp = ch + FIRST_Group(character.toString)
790 FIRST_Group(character.toString) = tmp.distinct
791 }
792 }
793 else {
794 FIRST_Group(character.toString) = value.toString
795 }
796 }
797
798 // case 2.2
799 if( judgeOnlyOneVoidSuccession(character.toString) == true ) {
800 if ( FIRST_Group.contains(character.toString) == true ) {
801 val tmp = "ε" + FIRST_Group(character.toString)
802 FIRST_Group(character.toString) = tmp.distinct
803 }
804 else {
805 FIRST_Group(character.toString) = "ε"
806 }
807 }
808 }
809
810 for( character <- wholeCharacters ) {
811 // case 3
812 // case 3.1
813 if( judgeCaseXY(character) == true ) {
814 val tmpReply = findCase_Y_In_XY(character)
815 for( eachTmpReply <- tmpReply ) {
816 if( FIRST_Group.contains(eachTmpReply.toString) == true ) {
817 for (ex <- FIRST_Group(eachTmpReply.toString)) {
818 if (ex != 'ε') {
819 if (FIRST_Group.contains(character.toString) == true) {
820 val tmp = ex.toString + FIRST_Group(character.toString)
821 FIRST_Group(character.toString) = tmp.distinct
822 }
823 else {
824 FIRST_Group(character.toString) = ex.toString
825 }
826 }
827 }
828 }
829 }
830 }
831
832 // case 3.2
833 if( findCase_Y_In_nY(character).length > 0 ) {
834 var flag = true
835 val tmpReply = findCase_Y_In_nY(character)
836
837 for( ex <- tmpReply ) {
838 if( localVN.contains(ex.toString) && FIRST_Group.contains(ex.toString) == true ) {
839 if( FIRST_Group(ex.toString).contains("ε") == false ) {
840 flag = false
841 }
842 }
843 else {
844 flag = false
845 }
846 if( flag == true ) {
847 if (FIRST_Group.contains(character.toString) == true) {
848 val tmp = FIRST_Group(ex.toString).replace( "ε", "" ) + FIRST_Group(character.toString)
849 FIRST_Group(character.toString) = tmp.distinct
850 }
851 else {
852 FIRST_Group(character.toString) = FIRST_Group(ex.toString).replace( "ε", "" )
853 }
854
855 }
856 }
857 }
858 // case 3.3
859 if( findCase_Y_In_nY(character).length > 0 ) {
860 var flag = true
861 val tmpReply = findCase_Y_In_nY(character)
862 for( ex <- tmpReply ) {
863 if( localVN.contains(ex.toString) && FIRST_Group.contains(ex.toString) == true ) {
864 if( FIRST_Group(ex.toString).contains("ε") == false ) {
865 flag = false
866 }
867 }
868 else {
869 flag = false
870 }
871 if( flag == true ) {
872
873 if (FIRST_Group.contains(character.toString) == true) {
874 val tmp = "ε" + FIRST_Group(character.toString)
875 FIRST_Group(character.toString) = tmp.distinct
876 }
877 else {
878 FIRST_Group(character.toString) = "ε"
879 }
880 }
881 }
882 }
883 }
884 }
885 FIRST_Group
886 }
887
888 /*
889 * Function name: FOLLOW
890 * Function description: 根据dfsFOLLOW函数,获取各个非终结符的FOLLOW集元素
891 * Input parameters: -ArrayBuffer[ (String, String) ](产生式左右两部分分别构成元组的第1个和第2个元素)
892 * Return value: -Map[ String, String ](Map的key是非终结符,value是其FOLLOW集元素)
893 * Exception: 未处理
894 * Author: 来自高山
895 * Created date: Sat Oct 19 2019 +0800
896 * Editor: 来自高山
897 * Edited Date: Sat Oct 19 2019 +0800
898 */
899 def FOLLOW( string: ArrayBuffer[ (String, String) ] ): Map[ String, String ] = {
900 val localVN = VN
901 val FOLLOW_Group = Map[ String, String ]()
902 for( ch <- localVN ) {
903 FOLLOW_Group(ch.toString) = dfsFOLLOW(ch.toString)
904 }
905 FOLLOW_Group
906 }
907
908 /*
909 * Function name: dfsFOLLOW
910 * Function description: 使用深度优先搜索(DFS)寻找各个非终结符的FOLLOW集元素
911 * Input parameters: -String(指定的非终结符)
912 * Return value: -String(指定终结符的FOLLOW集元素)
913 * Exception: 未处理
914 * Author: 来自高山
915 * Created date: Sat Oct 19 2019 +0800
916 * Editor: 来自高山
917 * Edited Date: Sat Oct 19 2019 +0800
918 */
919 def dfsFOLLOW( ch: String ): String = {
920 val FOLLOWPositions = Map[ String, String ]()
921 val FOLLOW_Group = Map[ String, String ]()
922 val localLL1_G = LL1_G
923 val FIRST_Group = FIRST(localLL1_G)
924 val localVN = VN
925 for( ch <- localVN ) {
926 FOLLOWPositions(ch.toString) = findGivenValueFOLLOWPosition(ch.toString)
927 FOLLOW_Group(ch.toString) = "#"
928 }
929 var result = ""
930
931 if( FOLLOWPositions(ch).length == 4 ) {
932 if( FOLLOWPositions(ch)(1).toString == "T" ) {
933 result += FIRST_Group( FOLLOWPositions(ch)(0).toString )
934 FOLLOW_Group(ch) += result.distinct
935 }
936 else if( FOLLOWPositions(ch)(3).toString == "T" ) {
937 result += FIRST_Group( FOLLOWPositions(ch)(2).toString )
938 FOLLOW_Group(ch) += result.distinct
939 }
940 if( FOLLOWPositions(ch)(1).toString == "W" ) {
941 result += dfsFOLLOW( FOLLOWPositions(ch)(0).toString )
942 FOLLOW_Group(ch) = result.distinct
943 }
944 else if( FOLLOWPositions(ch)(3).toString == "W" ) {
945 result += dfsFOLLOW( FOLLOWPositions(ch)(2).toString )
946 FOLLOW_Group(ch) = result.distinct
947 }
948 }
949
950 if( FOLLOWPositions(ch).length == 2 ) {
951 if( FOLLOWPositions(ch)(1).toString == "T" ) {
952 result += FIRST_Group( FOLLOWPositions(ch)(0).toString )
953 FOLLOW_Group(ch) = result.distinct
954 }
955 else if( FOLLOWPositions(ch)(1).toString == "W" ) {
956 result += dfsFOLLOW( FOLLOWPositions(ch)(0).toString )
957 FOLLOW_Group(ch) = result.distinct
958 }
959 }
960 FOLLOW_Group(ch).replace("ε", "")
961 }
962
963 /*
964 * Function name: findGivenValueFOLLOWPosition
965 * Function description: 按照教材P79右上角的算法描述,求解构成每个非终结符的FOLLOW集的“依赖”(因为实现了这个函数,节省了我原先用循环叠加求解FOLLOW集的700+代码)
966 * Input parameters: -String(指定终结符)
967 * Return value: -String(指定终结符的FOLLOW集元素,无则为空)
968 * Exception: 未处理
969 * Author: 来自高山
970 * Created date: Sat Oct 19 2019 +0800
971 * Editor: 来自高山
972 * Edited Date: Sat Oct 19 2019 +0800
973 */
974 def findGivenValueFOLLOWPosition( ch: String ): String = {
975 var result = ""
976 val cnt = new ArrayBuffer[String]()
977 val localRelations = relations
978
979 for( ex <- localRelations ) {
980 if( ex._3 != "א" ) {
981 if( ex._2.contains(ch) ) {
982 // מ
983 if( ex._2.length == 3 ) {
984 // B A α B β
985 if( ex._2(1).toString == ch && judgeCase2( ex._1, ex._2(0).toString, ch, ex._2(2).toString ) ) {
986 val value = ex._2(2).toString + "T"
987 if( cnt.contains(value) == false ) {
988 cnt += value
989 result += value
990 }
991 }
992 // B A α B β
993 if( ex._2(1).toString == ch && judgeCase3( ex._1, ex._2(0).toString, ch, ex._2(2).toString ) ) {
994 val value = ex._1.toString + "W"
995 if( cnt.contains(value) == false ) {
996 cnt += value
997 result += value
998 }
999 }
1000 }
1001 if( ex._2.length == 2 ) {
1002 // B A α B
1003 if( ex._2(1).toString == ch && judgeCase3( ex._1, ex._2(0).toString, ch, "" ) ) {
1004 val value = ex._1 + "W"
1005 if( cnt.contains(value) == false ) {
1006 cnt += value
1007 result += value
1008 }
1009 }
1010 }
1011 }
1012 if( ex._3.contains(ch) ) {
1013 if( ex._3.length == 3 ) {
1014 // B A α B β
1015 if( ex._3(1).toString == ch && judgeCase2( ex._1, ex._3(0).toString, ch, ex._3(2).toString ) ) {
1016 val value = ex._3(2).toString + "T"
1017 if( cnt.contains(value) == false ) {
1018 cnt += value
1019 result += value
1020 }
1021 }
1022 if( ex._3(1).toString == ch && judgeCase3( ex._1, ex._3(0).toString, ch, ex._3(2).toString ) ) {
1023 val value = ex._1 + "W"
1024 if( cnt.contains(value) == false ) {
1025 cnt += value
1026 result += value
1027 }
1028 }
1029 }
1030 if( ex._3.length == 2 ) {
1031 // B A α B
1032 if( ex._3(1).toString == ch && judgeCase3( ex._1, ex._3(0).toString, ch, "" ) ) {
1033 val value = ex._1 + "W"
1034 if( cnt.contains(value) == false ) {
1035 cnt += value
1036 result += value
1037 }
1038 }
1039 }
1040 }
1041 }
1042 else {
1043 if( ex._2.contains(ch) ) {
1044 if( ex._2.length == 3 ) {
1045 // B A α B β
1046 if( ex._2(1).toString == ch && judgeCase2( ex._1, ex._2(0).toString, ch, ex._2(2).toString ) ) {
1047 val value = ex._2(2).toString + "T"
1048 if( cnt.contains(value) == false ) {
1049 cnt += value
1050 result += value
1051 }
1052 }
1053 if( ex._2(1).toString == ch && judgeCase3( ex._1, ex._2(0).toString, ch, ex._2(2).toString ) ) {
1054 val value = ex._1 + "T"
1055 if( cnt.contains(value) == false ) {
1056 cnt += value
1057 result += value
1058 }
1059 }
1060 }
1061 if( ex._2.length == 2 ) {
1062 // B A α B
1063 if( ex._2(1).toString == ch && judgeCase3( ex._1, ex._2(0).toString, ch, "" ) ) {
1064 val value = ex._1 + "W"
1065 if( cnt.contains(value) == false ) {
1066 cnt += value
1067 result += value
1068 }
1069 }
1070 }
1071 }
1072 }
1073 }
1074 result
1075 }
1076
1077 /*
1078 * Function name: judgeCase2
1079 * Function description: 按照教材P79右下角的算法描述,判断是否填充满足条件(2)的矩阵元素
1080 * Input parameters: -String, String, String, String[分别代表条件(2)的四个字符]
1081 * Return value: -Boolean(满足条件(2)则返回true,否则返回false)
1082 * Exception: 未处理
1083 * Author: 来自高山
1084 * Created date: Tue Oct 15 2019 +0800
1085 * Editor: 来自高山
1086 * Edited Date: Tue Oct 15 2019 +0800
1087 */
1088 def judgeCase2( A: String, α: String, B: String, β: String ): Boolean = {
1089 val localVN = VN
1090 val wholeCharacters = allCharacters
1091 val localLL1_G = LL1_G
1092 val localFIRST = FIRST(localLL1_G)
1093 if( localVN.contains(A) == true && wholeCharacters.contains(α) == true && localVN.contains(B) == true &&
1094 wholeCharacters.contains(β) && localFIRST.contains(β) == true ) {
1095 true
1096 }
1097 else {
1098 false
1099 }
1100 }
1101
1102 /*
1103 * Function name: judgeCase3
1104 * Function description: 按照教材P79右下角的算法描述,判断是否填充满足条件(3)的矩阵元素
1105 * Input parameters: -String, String, String, String[分别代表条件(3)的四个字符]
1106 * Return value: -Boolean(满足条件(3)则返回true,否则返回false)
1107 * Exception: 未处理
1108 * Author: 来自高山
1109 * Created date: Wed Oct 16 2019 +0800
1110 * Editor: 来自高山
1111 * Edited Date: Wed Oct 16 2019 +0800
1112 */
1113 def judgeCase3( A: String, α: String, B: String, β: String ): Boolean = {
1114 val localVN = VN
1115 val wholeCharacters = allCharacters
1116 val localLL1_G = LL1_G
1117 val localFIRST = FIRST(localLL1_G)
1118 if( ( localVN.contains(A) == true && wholeCharacters.contains(α) == true && localVN.contains(B) == true ) ||
1119 ( localVN.contains(A) == true && wholeCharacters.contains(α) == true && localVN.contains(B) == true && localFIRST(β).contains("ε") == true ) ) {
1120 true
1121 }
1122 else {
1123 false
1124 }
1125 }
1126
1127 /*
1128 * Function name: initiateMatrix
1129 * Function description: 初始化分析表(为了在控制台打印方便,表长为非终结符个数加一,表宽为终结符个数加一)
1130 * Input parameters: 无
1131 * Return value: -Array[ Array[ String] ](分析表矩阵元素构成的二维数组,除了第0行和第0列,其它列与行的元素均为null)
1132 * Exception: 未处理
1133 * Author: 来自高山
1134 * Created date: Wed Oct 16 2019 +0800
1135 * Editor: 来自高山
1136 * Edited Date: Wed Oct 16 2019 +0800
1137 */
1138 def initiateMatrix(): Array[ Array[ String] ] = {
1139 val localVN = VN
1140 val localVT = VT
1141 val result = Array.ofDim[String](localVN.length + 1, localVT.length + 1)
1142 for( i <- 1 to localVN.length ) {
1143 result(i)(0) = localVN(i - 1).toString
1144 }
1145 for( j <- 1 to localVT.length ) {
1146 if( localVT(j - 1).toString == "ε" ) {
1147 result(0)(j) = "#"
1148 }
1149 else {
1150 result(0)(j) = localVT(j - 1).toString
1151 }
1152 }
1153 result
1154 }
1155
1156 /*
1157 * Function name: createMatrix
1158 * Function description: 按照教材P79右下角的算法描述,构造分析表
1159 * Input parameters: 无
1160 * Return value: -Array[ Array[String] ](分析表矩阵元素构成的二维数组)
1161 * Exception: 未处理
1162 * Author: 来自高山
1163 * Created date: Wed Oct 16 2019 +0800
1164 * Editor: 来自高山
1165 * Edited Date: Wed Oct 16 2019 +0800
1166 */
1167 def createMatrix(): Array[ Array[String] ] = {
1168 val result = initiateMatrix()
1169 val localVT = VT
1170 val localRelations = relations
1171 val localLL1_G = LL1_G
1172 val localFIRST = FIRST(localLL1_G)
1173 val localFOLLOW = FOLLOW(localLL1_G)
1174
1175 for( ex <- localRelations ) {
1176
1177 if( ex._3 != "א" ) {
1178 for( a <- localVT ) {
1179 val ex2Length = ex._2.length
1180 var range = ""
1181 var α = ""
1182 var flag = false
1183 for( x <- 0 to (ex2Length - 1) ) {
1184 if( localFIRST( ex._2(x).toString ).contains("ε") == false && flag == false ) {
1185 α = ex._2(x).toString
1186 range = localFIRST( α )
1187 flag = true
1188 }
1189 }
1190 if( range.contains(a) == true && flag == true ) {
1191 result(getRow(ex._1))(getColumn(a.toString)) = ex._1 + "->" + ex._2
1192 }
1193 if( flag == false ) {
1194 range = "ε"
1195 result( getRow(ex._1) )( getColumn("ε") ) = ex._1 + "->" + "ε"
1196 }
1197
1198 // case 3
1199 if( range.contains("ε") == true && flag == false ) {
1200 for( b <- localFOLLOW(α) ) {
1201 result( getRow(ex._1.toString) )( getColumn(b.toString) ) = ex._1 + "->" + ex._2 // t --> tx
1202 }
1203 }
1204
1205 val ex3Length = ex._3.length
1206 range = ""
1207 flag = false
1208 for( x <- 0 to (ex3Length - 1) ) {
1209 if( localFIRST( ex._3(x).toString ).contains("ε") == false && flag == false ) {
1210 α = ex._3(x).toString
1211 range = localFIRST( α )
1212 flag = true
1213 }
1214 }
1215 if( range.contains(a) == true && flag == true ) {
1216 result( getRow(ex._1) )( getColumn(a.toString) ) = ex._1 + "->" + ex._3
1217 }
1218 if( flag == false ) {
1219 range = "ε"
1220 result(getRow(ex._1))(getColumn("ε")) = ex._1 + "->" + "ε"
1221 }
1222
1223 // case 3
1224 if( range.contains("ε") == true && flag == false ) {
1225 for( b <- localFOLLOW(ex._1) ) {
1226 result( getRow(ex._1.toString) )( getColumn(b.toString) ) = ex._1 + "->" + ex._3 // t --> tx
1227 }
1228 }
1229 }
1230 }
1231
1232 else {
1233 for( a <- localVT ) {
1234 val ex2Length = ex._2.length
1235 var range = ""
1236 var α = ""
1237 var flag = false
1238 for( x <- 0 to (ex2Length - 1) ) {
1239 if( localFIRST( ex._2(x).toString ).contains("ε") == false && flag == false ) {
1240 α = ex._2(x).toString
1241 range = localFIRST(α)
1242 flag = true
1243 }
1244 }
1245 if( range.contains(a) == true && flag == true ) {
1246 result( getRow(ex._1) )( getColumn(a.toString) ) = ex._1 + "->" + ex._2
1247 }
1248 if( flag == false ) {
1249 range = "ε"
1250 result( getRow(ex._1) )( getColumn("ε") ) = ex._1 + "->" + "ε"
1251 }
1252
1253 // case 3
1254 if( range.contains("ε") == true && flag == false ) {
1255 for( b <- localFOLLOW(ex._1) ) {
1256 result( getRow(ex._1.toString) )( getColumn(b.toString) ) = ex._1 + "->" + ex._2
1257 }
1258 }
1259 }
1260 }
1261 }
1262 result
1263 }
1264
1265 /*
1266 * Function name: getRow
1267 * Function description: 获取指定字符在分析表中的行数
1268 * Input parameters: -String(指定字符)
1269 * Return value: -Int(指定字符所在的行数)
1270 * Exception: 未处理
1271 * Author: 来自高山
1272 * Created date: Wed Oct 16 2019 +0800
1273 * Editor: 来自高山
1274 * Edited Date: Wed Oct 16 2019 +0800
1275 */
1276 def getRow( ch: String ): Int = {
1277 val matrix = initiateMatrix()
1278 var result = -1
1279 if( ch == "α" ) {
1280 println( "1 --- getRow, ch == " + ch )
1281 }
1282 for( i <- 0 to (matrix.length - 1) ) {
1283 if( matrix(i)(0) == ch ) {
1284 result = i
1285 }
1286 }
1287 result
1288 }
1289
1290 /*
1291 * Function name: getColumn
1292 * Function description: 获取指定字符在分析表中的列数
1293 * Input parameters: -String(指定字符)
1294 * Return value: -Int(指定字符所在的列数)
1295 * Exception: 未处理
1296 * Author: 来自高山
1297 * Created date: Wed Oct 16 2019 +0800
1298 * Editor: 来自高山
1299 * Edited Date: Wed Oct 16 2019 +0800
1300 */
1301 def getColumn( ch: String ): Int = {
1302 val matrix = initiateMatrix()
1303 var result = -1
1304 for( i <- 0 to (matrix.length - 1) ) {
1305 for( j <- 0 to (matrix(i).length - 1) ) {
1306 if( matrix(0)(j) == ch ) {
1307 result = j
1308 }
1309 if( matrix(0)(j) == "#" && ch == "ε" ) {
1310 result = j
1311 }
1312 }
1313 }
1314 result
1315 }
1316
1317 /*
1318 * Function name: analyse
1319 * Function description: 对指定的字符串进行LL(1)分析
1320 * Input parameters: -String(输入的指定字符串)
1321 * Return value: -Boolean(分析成功则返回true,否则false)
1322 * Exception: 未处理(有出错提示)
1323 * Author: 来自高山
1324 * Created date: Wed Oct 16 2019 +0800
1325 * Editor: 来自高山
1326 * Edited Date: Wed Oct 16 2019 +0800
1327 */
1328 def analyse( expression: String ): Boolean = {
1329 val stack = new mutable.Stack[String]()
1330 var localExpression = expression
1331 val table = createMatrix()
1332 val localVT = VT
1333 val localVN = VN
1334 val localRelations = relations
1335
1336 stack.push("#")
1337 stack.push( localRelations(0)._1 )
1338
1339 var cnt = 0
1340 staticAnalyseList.append(new Analyse("步骤","分析栈","剩余字符串","所用产生式","动作"));
1341 staticAnalyseList.append(new Analyse(cnt.toString, displayStack(stack).reverse.toString,localExpression.toString,"","initiate"));
1342 while( stack.isEmpty == false ) {
1343 val stackTop = stack.top
1344 stack.pop()
1345 // 栈顶符号属于 非终结符
1346 if( localVN.contains(stackTop) == true ) {
1347 // 栈顶符号与表达式左端首字符 存在 关系
1348 if( table( getRow(stackTop) )( getColumn( localExpression(0).toString ) ) != null ) {
1349 val lastHalf = table( getRow(stackTop) )( getColumn( localExpression(0).toString ) ).split( "->", 2 ).last
1350 val length = lastHalf.length
1351 for( i <- 0 to (length - 1) ) {
1352 if( lastHalf != "ε" ) {
1353 stack.push(lastHalf(length - 1 - i).toString)
1354 }
1355 }
1356 cnt += 1
1357
1358 if( lastHalf != "ε" ) {
1359 staticAnalyseList.append(new Analyse(cnt.toString, displayStack(stack).reverse.toString, localExpression.toString, table(getRow(stackTop))(getColumn(localExpression(0).toString)), "POP, PUSH(" + lastHalf.reverse + ")"));
1360 }
1361 else {
1362 staticAnalyseList.append(new Analyse(cnt.toString, displayStack(stack).reverse.toString, localExpression.toString, table(getRow(stackTop))(getColumn(localExpression(0).toString)), "POP"));
1363 }
1364 }
1365 // 栈顶符号与表达式左端首字符 不存在 关系
1366 else {
1367 // 栈顶符号 等于 表达式左端首字符
1368 if( stackTop == "#" && localExpression(0).toString == "#" ) {
1369 println("11111")
1370 return true
1371 }
1372 // 栈顶符号 不等于 表达式左端首字符
1373 else {
1374 println("1 - error")
1375 staticAnalyseList.append(new Analyse(cnt.toString, displayStack(stack).reverse.toString,localExpression.toString,"",""));
1376 return false
1377 }
1378 }
1379 }
1380 // 栈顶符号属于 终结符
1381 if( localVT.contains(stackTop) == true ) {
1382 // 栈顶符号 等于 表达式左端首字符
1383 if( stackTop == localExpression(0).toString ) {
1384 if( stackTop == localExpression(0).toString ) {
1385 //stack.pop()
1386 localExpression = localExpression.drop(1)
1387 cnt += 1
1388 staticAnalyseList.append(new Analyse(cnt.toString, displayStack(stack).reverse.toString,localExpression.toString,"","GETNEXT(" + stackTop + ")"));
1389 }
1390 // 栈顶符号 不等于 表达式左端首字符
1391 else {
1392 println("2 - error")
1393 return false
1394 }
1395 }
1396 }
1397 }
1398
1399 true
1400 }
1401
1402 /*
1403 * Function name: judgeLeftRecursion
1404 * Function description: 判断是否存在形式上的左递归
1405 * Input parameters: -(String, String, String)(产生式的左端与右端的两个(或为1个)元素)
1406 * Return value: -Int(0表示无,1表示右端第1个元素存在形式上的左递归,2表示右端第2个元素)
1407 * Exception: 未处理
1408 * Author: 来自高山
1409 * Created date: Sat Oct 19 2019 +0800
1410 * Editor: 来自高山
1411 * Edited Date: Sat Oct 19 2019 +0800
1412 */
1413 def judgeLeftRecursion( expression: (String, String, String) ): Int = {
1414 var ans = 0 // ans = 0 means the current expression is not involved left-recursion
1415 if( expression._2.length >= 2 && expression._1 == expression._2(0).toString && expression._2.drop(1) != "ε" ) {
1416 ans += 1 // ans = 1 means the left recursion involves the expression._2
1417 }
1418 if( expression._3.length >= 2 && expression._1 == expression._3(0).toString && expression._3.drop(1) != "ε" ) {
1419 ans += 2 // ans = 2 means the left recursion involves the expression._3
1420 }
1421 ans // ans = 3 means the given expression is false since both exp(2) and exp(3) involved
1422 }
1423
1424 /*
1425 * Function name: eliminateLeftRecursion
1426 * Function description: 消除形式上的左递归
1427 * Input parameters: 无
1428 * Return value: -ArrayBuffer[ (String, String, String) ](消除左递归后的新文法)
1429 * Exception: 未处理
1430 * Author: 来自高山
1431 * Created date: Sat Oct 19 2019 +0800
1432 * Editor: 来自高山
1433 * Edited Date: Sat Oct 19 2019 +0800
1434 */
1435 def eliminateLeftRecursion(): ArrayBuffer[ (String, String, String) ] = {
1436 var localRelations = relations
1437 var invalidRelations = new ArrayBuffer[ (String, String, String) ]()
1438 val localCandidateLetters = allCandidateLetters
1439 val VN1 = "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩABCDEFGHIJKLMNOPQRSTUVWXYZ"
1440 val VT1 = "αβγδεζηθικλμνξοπρστυφχψωabcdefghijklmnopqrstuvwxyz"
1441 for( ex <- localRelations ) {
1442 if( ex._3 != "א" ) {
1443 if( judgeLeftRecursion( ex._1, ex._2, ex._3 ) == 1 ) {
1444 // P = ex._1, α = ex._2 - ex._1, β = ex._3, P' = newValue
1445 invalidRelations += ( ( ex._1, ex._2, ex._3 ) )
1446 val newValue = subString( usedCharacters, localCandidateLetters )(0)
1447 usedCharacters += newValue
1448 if( VN1.contains(newValue) && !VN.contains(newValue) ) {
1449 VN += newValue.toString
1450 allCharacters += newValue.toString
1451 }
1452 if( VT1.contains(newValue) && !VT.contains(newValue) ) {
1453 VT += newValue.toString
1454 allCharacters += newValue.toString
1455 }
1456 val α = ex._2.drop(1)
1457 val exp1 = ( ex._1, ex._3 + newValue.toString, "א" )
1458 val exp2 = ( newValue.toString, α.toString + newValue.toString, "ε" )
1459 // println( "1 -- exp1._1 = " + exp1._1 + ", exp1._2 = " + exp1._2 + ", exp1._3 = " + exp1._3 )
1460 // println( "1 -- exp2._1 = " + exp2._1 + ", exp2._2 = " + exp2._2 + ", exp2._3 = " + exp2._3 )
1461 localRelations += exp1
1462 localRelations += exp2
1463 }
1464 else if( judgeLeftRecursion( ex._1, ex._2, ex._3 ) == 2 ) {
1465 // P = ex._1, α = ex._3 - ex._1, β = ex._3, P' = newValue
1466 invalidRelations += ( ( ex._1, ex._2, ex._3 ) )
1467 val newValue = subString( usedCharacters, localCandidateLetters )(0)
1468 if( VN1.contains(newValue) && !VN.contains(newValue) ) {
1469 VN += newValue.toString
1470 allCharacters += newValue.toString
1471 }
1472 if( VT1.contains(newValue) && !VT.contains(newValue) ) {
1473 VT += newValue.toString
1474 allCharacters += newValue.toString
1475 }
1476 usedCharacters += newValue
1477 val α = ex._3.drop(1)
1478 val exp1 = ( ex._1, ex._3 + newValue.toString, "א" )
1479 val exp2 = ( newValue.toString, α.toString + newValue.toString, "ε" )
1480 // println( "2 -- exp1._1 = " + exp1._1 + ", exp1._2 = " + exp1._2 + ", exp1._3 = " + exp1._3 )
1481 // println( "2 -- exp2._1 = " + exp2._1 + ", exp2._2 = " + exp2._2 + ", exp2._3 = " + exp2._3 )
1482 localRelations += exp1
1483 localRelations += exp2
1484 }
1485 else if( judgeLeftRecursion( ex._1, ex._2, ex._3 ) == 3 ){
1486 println( "error in the function eliminateLeftRecursion" )
1487 }
1488 }
1489 else {
1490 if( judgeLeftRecursion( ex._1, ex._2, ex._3 ) == 1 ) {
1491 // P = ex._1, α = ex._2 - ex._1, β = ex._3, P' = newValue
1492 invalidRelations += ( ( ex._1, ex._2, ex._3 ) )
1493 val newValue = subString( usedCharacters, localCandidateLetters )(0)
1494 if( VN1.contains(newValue) && !VN.contains(newValue) ) {
1495 VN += newValue.toString
1496 allCharacters += newValue.toString
1497 }
1498 if( VT1.contains(newValue) && !VT.contains(newValue) ) {
1499 VT += newValue.toString
1500 allCharacters += newValue.toString
1501 }
1502 usedCharacters += newValue
1503 val α = ex._2.drop(1)
1504 val exp1 = ( ex._1, newValue.toString, "א" )
1505 val exp2 = ( newValue.toString, α.toString + newValue.toString, "ε" )
1506 // println( "3 -- exp1._1 = " + exp1._1 + ", exp1._2 = " + exp1._2 + ", exp1._3 = " + exp1._3 )
1507 // println( "3 -- exp2._1 = " + exp2._1 + ", exp2._2 = " + exp2._2 + ", exp2._3 = " + exp2._3 )
1508 localRelations += exp1
1509 localRelations += exp2
1510 }
1511 }
1512 }
1513 for( ex <- invalidRelations ) {
1514 localRelations = localRelations.-(ex)
1515 }
1516 relations = localRelations
1517 localRelations
1518 }
1519
1520 /*
1521 * Function name: subString
1522 * Function description: 获取两输入字符串的差集(要求两者均非空)
1523 * Input parameters: 无
1524 * Return value: -String(两输入字符串的差集)
1525 * Exception: 未处理
1526 * Author: 来自高山
1527 * Created date: Sat Oct 19 2019 +0800
1528 * Editor: 来自高山
1529 * Edited Date: Sat Oct 19 2019 +0800
1530 */
1531 def subString( usedCharacters: String, localCandidateLetters: String ): String = {
1532 require( usedCharacters.length != 0 && localCandidateLetters.length != 0 )
1533 var ans = ""
1534 var A = usedCharacters
1535 var B = localCandidateLetters
1536 if( A.length < B.length ) {
1537 val tmp = A
1538 A = B
1539 B = tmp
1540 }
1541 for( i <- 0 to (A.length - 1) ) {
1542 var j = 0
1543 while( j < B.length && B(j) != A(i) ) {
1544 j += 1
1545 }
1546 if( j == B.length ) {
1547 ans += A(i)
1548 }
1549 }
1550 ans
1551 }
1552 }
FileUtil class类(Java):
1 import java.io.*;
2 import java.util.Vector;
3
4 /**
5 * 文件工具类
6 */
7 public class FileUtil {
8 public static void main(String[] args) throws FileNotFoundException {
9 String s = readFile( new FileInputStream("/home/hadoop001/Desktop/test.data") );
10 System.out.println(s);
11 }
12 /**
13 * 读取文件内容
14 *
15 * @param is
16 * @return
17 */
18 public static String readFile(InputStream is) {
19 BufferedReader br = null;
20 StringBuffer sb = new StringBuffer();
21 try {
22 br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
23 String readLine = null;
24 while ((readLine = br.readLine()) != null) {
25 sb.append(readLine+"\r\n");
26 }
27 } catch (Exception e) {
28 e.printStackTrace();
29 } finally {
30 try {
31 br.close();
32 is.close();
33 } catch (IOException e) {
34 e.printStackTrace();
35 }
36 }
37 return sb.toString();
38 }
39 }
包pojo中的Analyse class类(Java):
1 package pojo;
2
3 public class Analyse {
4 private String step;
5 private String analysisStack;
6 private String remainingString;
7 private String productionType;
8 private String action;
9
10 public Analyse(){
11
12 }
13
14 public Analyse(String step, String analysisStack, String remainingString, String productionType, String action) {
15 this.step = step;
16 this.analysisStack = analysisStack;
17 this.remainingString = remainingString;
18 this.productionType = productionType;
19 this.action = action;
20 }
21
22 public String getStep() {
23 return step;
24 }
25
26 public void setStep(String step) {
27 this.step = step;
28 }
29
30 public String getAnalysisStack() {
31 return analysisStack;
32 }
33
34 public void setAnalysisStack(String analysisStack) {
35 this.analysisStack = analysisStack;
36 }
37
38 public String getRemainingString() {
39 return remainingString;
40 }
41
42 public void setRemainingString(String remainingString) {
43 this.remainingString = remainingString;
44 }
45
46 public String getProductionType() {
47 return productionType;
48 }
49
50 public void setProductionType(String productionType) {
51 this.productionType = productionType;
52 }
53
54 public String getAction() {
55 return action;
56 }
57
58 public void setAction(String action) {
59 this.action = action;
60 }
61 }
程序截图:
图 1 开始界面
图 2 选择文件
图 3 显示当前文法
图 4 执行程序(输入表达式为“i+i*i”)
图 5 执行程序(输入表达式为“i+i*i-i/i”)