JavaCC语法分析实验二

本文档详述了一次使用JavaCC构建MiniC语法分析器的实验过程。实验目标是理解JavaCC的工作原理,设计并实现MiniC的上下文无关文法,生成递归下降分析程序以分析C语言程序,输出语法树。实验内容包括定义MiniC文法,编写JJT模板文件,实现main方法读取源程序并进行语法分析,以及展示输入/输出示例。源代码中包含了Start部分、main方法部分和完整的JJT源代码。实验结果展示了两个MiniC程序的分析和对应的语法树。


JavaCC 语法分析实验二

一、实验目的:

  1. 掌握 JavaCC 语法分析器工作原理;
  2. 设计 MiniC 的上下文无关文法,在“Parser.jjt”文件中表示该文法,生
    成调试递归下降分析程序,以便对任意输入的符号串进行分析;
  3. 输出语法树。

二、MiniC 语法

〈程序〉 → int main() {〈语句块〉* }
〈语句块〉 →〈语句〉| {〈语句块〉* }
〈语句〉 →〈顺序语句〉|〈条件语句〉|〈循环语句〉
〈顺序语句〉→ (〈声明语句〉| 〈赋值语句〉) ”;” 〈声明语句〉→ int ID,ID,…,ID //思考如何表示
〈赋值语句〉→ ID =〈表达式〉
〈条件语句〉→ if (〈条件〉)〈语句块〉 else 〈语句块〉
〈循环语句〉→ while (〈条件〉)〈语句块〉
〈条件〉 →〈表达式〉〈关系符〉〈表达式〉
〈表达式〉 → // 可以使用javacc自动生成的 表达式(Expression)的文法
〈关系符〉 → <| <=| >| >= | ==| !=
注意:该文法为参考文法,可以对其适当修改。首先,文件中的文法必须
不含左递归和回溯;其次,同学们可以补充其它语法规则,如布尔表达式,for
语句等。

三、实习要求

  1. 以文件流的形式读入要分析的 C 语言程序;
  2. 如果输入的源程序符合 MiniC 的语法规范,输出语法树。
    扩展要求:具有错误检查的能力,可以输出错误所在的行号,并简单提
    示。

四、实验过程和指导:

  1. 新建一个用于 javacc 编辑的 jjt 模板文件:
    (1)新建 java 项目
    (2)建立一个语法分析包(例如:package parser)
    (3)在 parser 包内,“新建”-“其它”-“JavaCC Template File”
    (4)创建一个“.jjt”文件,如图 1 所示,建议选用“Non staitc”模式:
    图 1 新建 jjt 模板文件

  2. 在模板文件中修改词法部分和语法部分(如图 2 所示),将 MiniC 的文法依照要求写入 jjt 文件。

  3. 修改 jjt 文件的 main 方法(如图 2 所示),使其执行任务是:指定要进
    行语法分析的源程序,执行语法分析,输出语法树。
    在这里插入图片描述

五、程序输入/输出示例:

要求:测试多组源程序查看结果。
图 3 和图 4 为一组作为参考的测试源代码及其对应的语法树,具体的语法
树节点来自于同学们自定义的文法。
注意:文法的定义不同,语法树的层级关系则不同。
在这里插入图片描述
在这里插入图片描述

六.实验jjt源代码:

1.Start部分

impleNode Start() :
{}
{
  Program()
  {
    return jjtThis;
  }
}
 
void Program() :
{}
{
 < INT>
 < MAIN>
 < LBRACE>
 < RBRACE>
 < BLBRACE>
    (SentenceBlock())*
    (
      ReturnSent()
    )
 < BRBRACE>
}
 
void SentenceBlock():
{}
{
  Sentence()
| < BLBRACE>
(SentenceBlock())*
< BRBRACE>
}
 
void Sentence() :
{}
{
  SequenceSen()
  | ConditionSen()
  | LoopSent()
}
 
void SequenceSen() :
{}
{
   [
      AssigmentSen()
    | DeclareSen()
   ]
  < SEMICOLON>
}
 
void DeclareSen() :
{}
{
  [
       <INT>
   | <DOUBLE>
   | <FLOAT>
   | <CHAR>
  ]
   Identifier()
   (<COMMA> Identifier())*
}
 
void AssigmentSen() :
{}
{
  Identifier()
  <ASSIGN>
  Expression()
}
 
void ConditionSen() :
{}
{
  <IF>
   Condition()
   SentenceBlock()
}
 
void LoopSent() :
{}
{
  <WHILE>
  Condition()
  SentenceBlock()
}
 
void Condition() :
{}
{
  "("
  Expression()
  Relations()
  Expression()
  ")"
}
   
void Expression() :
{}
{
  AdditiveExpression()
}
 
void AdditiveExpression() :
{}
{
  MultiplicativeExpression()
  (
    (
      "+"
    | "-"
    )
    MultiplicativeExpression()
  )*
}
 
void MultiplicativeExpression() :
{}
{
  UnaryExpression()
  (
    (
      "*"
    | "/"
    | "%"
    )
    UnaryExpression()
  )*
}
 
void UnaryExpression() :
{}
{
  "(" Expression() ")"
| Identifier()
| Integer()
}
 
void Identifier() :
{}
{
  < IDENTIFIER >
}
 
void Integer() :
{}
{
  < INTEGER_LITERAL >
}
 
void Relations() :
{}
{
  <GT>
  | <LT>
  | <EQUAL>
}
 
void ReturnSent() :
{}
{
    < RETURN > <INTEGER_LITERAL> < SEMICOLON>
}

2.main方法部分

import java.io.FileReader;
import java.io.FileNotFoundException;
public class WorkGrammar
{
  public static void main(String args [])throws FileNotFoundException
  {
   System.out.println("语法分析");
   FileReader Fr = new FileReader("test3.txt"); 
    new WorkGrammar(Fr);
    try
    {
      SimpleNode n = WorkGrammar.Start();
      n.dump("");
      System.out.println("END");
    }
    catch (Exception e)
    {
      System.out.println("Oops.");
      System.out.println(e.getMessage());
    }
  }
}

3.源jjt代码

/**
 * JJTree template file created by SF JavaCC plugin 1.5.28+ wizard for JavaCC 1.5.0+
 */
options
{
  static = true;
}

PARSER_BEGIN(WorkGrammar)
package WorkGrammar;
import java.io.FileReader;
import java.io.FileNotFoundException;
public class WorkGrammar
{
  public static void main(String args [])throws FileNotFoundException
  {
   System.out.println("语法分析");
   FileReader Fr = new FileReader("test.txt"); 
    new WorkGrammar(Fr);
    try
    {
      SimpleNode n = WorkGrammar.Start();
      n.dump("");
      System.out.println("END");
    }
    catch (Exception e)
    {
      System.out.println("Oops.");
      System.out.println(e.getMessage());
    }
  }
}

PARSER_END(WorkGrammar)


SKIP :
{
  " "
| "\t"
| "\n"
| "\r"
| < "//" (~[ "\n", "\r" ])*
    (
      "\n"
    | "\r"
    | "\r\n"
    ) >
| < "/*" (~[ "*" ])* "*"
    (
      ~[ "/" ] (~[ "*" ])* "*"
    )*
    "/" >
}
TOKEN : /* KEYS */
{
  < INT : "int" >
| < DOUBLE : "double" >
| < FLOAT : "float" >
| < CHAR : "char" >
| < VOID : "void" >
| < FOR : "for" >
| < WHILE : "while" >
| < RETURN : "return" >
| < IF : "if" >
| 	< MAIN:"main">
}
TOKEN : /* LITERALS */
{
  < INTEGER_LITERAL :
    < DECIMAL_LITERAL > ([ "l", "L" ])?
  | < HEX_LITERAL > ([ "l", "L" ])?
  | < OCTAL_LITERAL > ([ "l", "L" ])? 
    >
| < #DECIMAL_LITERAL : [ "1"-"9" ] ([ "0"-"9" ])* >
| < #HEX_LITERAL : "0" [ "x", "X" ] ([ "0"-"9", "a"-"f", "A"-"F" ])+ >
| < #OCTAL_LITERAL : "0" ([ "0"-"7" ])* >
}
TOKEN : /* OPERATORS */
{
  < PLUS : "+" >
| < MINUS : "-" >
| < MULTIPLY : "*" >
| < DIVIDE : "/" >
| < ASSIGN : "=" >
| < GT : ">" >
| < LT : "<" >
| < EQUAL : "==" >
}

TOKEN : /* SEPARATER */
{
  < QUATION : "\"" >
| < SEMICOLON : ";" >
| < BLBRACE : "{" >
| < BRBRACE : "}" >
| < LBRACE : "(" >
| < RBRACE : ")" >
| < COMMA : "," >
| < EXCLA_SYM : "!" >
}
TOKEN : /* IDENTIFIERS */
{
  < IDENTIFIER :
    < LETTER >
    (
      < LETTER >
    | < DIGIT >
    )* >
| < #LETTER : [ "_", "a"-"z", "A"-"Z" ] >
| < #DIGIT : [ "0"-"9" ] >
}

SimpleNode Start() :
{}
{
  Program()
  {
    return jjtThis;
  }
}

void Program() :
{}
{
 < INT>
 < MAIN>
 < LBRACE>
 < RBRACE>
 < BLBRACE>
	(SentenceBlock())*
	(
	  ReturnSent()
	)
 < BRBRACE>
}

void SentenceBlock():
{}
{
  Sentence()
| < BLBRACE>
(SentenceBlock())*
< BRBRACE>
}

void Sentence() :
{}
{
  SequenceSen()
  | ConditionSen()
  | LoopSent()
}

void SequenceSen() :
{}
{
   [
      AssigmentSen()
    | DeclareSen()
   ]
  < SEMICOLON>
}

void DeclareSen() :
{}
{
  [
  	 <INT>
   | <DOUBLE>
   | <FLOAT>
   | <CHAR>
  ]
   Identifier()
   (<COMMA> Identifier())*
}

void AssigmentSen() :
{}
{
  Identifier()
  <ASSIGN>
  Expression()
}

void ConditionSen() :
{}
{
  <IF>
   Condition()
   SentenceBlock()
}

void LoopSent() :
{}
{
  <WHILE>
  Condition()
  SentenceBlock()
}

void Condition() :
{}
{
  "("
  Expression()
  Relations()
  Expression()
  ")"
}
  
void Expression() :
{}
{
  AdditiveExpression()
}

void AdditiveExpression() :
{}
{
  MultiplicativeExpression()
  (
    (
      "+"
    | "-"
    )
    MultiplicativeExpression()
  )*
}

void MultiplicativeExpression() :
{}
{
  UnaryExpression()
  (
    (
      "*"
    | "/"
    | "%"
    )
    UnaryExpression()
  )*
}

void UnaryExpression() :
{}
{
  "(" Expression() ")"
| Identifier()
| Integer()
}

void Identifier() :
{}
{
  < IDENTIFIER >
}

void Integer() :
{}
{
  < INTEGER_LITERAL >
}

void Relations() :
{}
{
  <GT>
  | <LT>
  | <EQUAL>
}

void ReturnSent() :
{}
{
	< RETURN > <INTEGER_LITERAL> < SEMICOLON>
}

七.实验结果

//实验测试一
int main(){
    int a,b;
    a = 23;
   while(a>2){
       int x;
       x = a+b;     
   }
   return 0;
}

在这里插入图片描述

//实验测试二
int main(){
    int a,b;
    a=1;
    b=3;
   if(a<b){
       int x;
       x = a;
       a = b;
       b = x;     
   }
   return 0;
}

在这里插入图片描述

【问题描述】 请根据给定的文法设计并实现词法分析程序,从源程序中识别出单词,记录其单词类别和单词值,输入输出及处理要求如下: (1)数据结构和与语法分析程序的接口请自行定义;类别码需按下表格式统一定义; (2)为了方便进行自动评测,输入的被编译源文件统一命名为testfile.txt(注意不要写错文件名);输出的结果文件统一命名为output.txt(注意不要写错文件名),结果文件中每行按如下方式组织: 单词类别码 单词的字符/字符串形式(中间仅用一个空格间隔) 单词的类别码请统一按如下形式定义: 单词名称 类别码 单词名称 类别码 单词名称 类别码 单词名称 类别码 标识符 IDENFR else ELSETK - MINU = ASSIGN 整形常量 INTCON switch SWITCHTK * MULT ; SEMICN 字符常量 CHARCON case CASETK / DIV , COMMA 字符串 STRCON default DEFAULTTK < LSS ( LPARENT const CONSTTK while WHILETK GRE [ LBRACK char CHARTK scanf SCANFTK >= GEQ ] RBRACK void VOIDTK printf PRINTFTK == EQL { LBRACE main MAINTK return RETURNTK != NEQ } RBRACE if IFTK + PLUS : COLON 【输入形式】testfile.txt中的符合文法要求的测试程序。 【输出形式】要求将词法分析结果输出至output.txt中。 【特别提醒】(1)读取的字符串要原样保留着便于输出,特别是数字,这里输出的并不是真正的单词值,其实是读入的字符串,单词值需另行记录。 (2)本次作业只考核对正确程序的处理,但需要为今后可能出现的错误情况预留接口。 (3)在今后的错误处理作业中,需要输出错误的行号,在词法分析的时候注意记录该信息。 (4)单词的类别和单词值以及其他关注的信息,在词法分析阶段获取后,后续的分析阶段会使用,请注意记录;当前要求的输出只是为了便于评测,完成编译器中无需出现这些信息,请设计为方便打开/关闭这些输出的方案。 【文法定义】请到“2020年文法定义(用于查看文法,不计入成绩)”作业中查看文法 【样例输入】 coNst int cONst1 = 001, const2 = -100; const char const3 = '_'; int change1; char change3; int gets1(int var1,int var2){ change1 = var1 + var2; return (change1); } void main(){ printf("Hello World"); printf(gets1(10, 20)); } 【样例输出】 CONSTTK coNst INTTK int IDENFR cONst1 ASSIGN = INTCON 001 COMMA , IDENFR const2 ASSIGN = MINU - INTCON 100 SEMICN ; CONSTTK const CHARTK char IDENFR const3 ASSIGN = CHARCON _ SEMICN ; INTTK int IDENFR change1 SEMICN ; CHARTK char IDENFR change3 SEMICN ; INTTK int IDENFR gets1 LPARENT ( INTTK int IDENFR var1 COMMA , INTTK int IDENFR var2 RPARENT ) LBRACE { IDENFR change1 ASSIGN = IDENFR var1 PLUS + IDENFR var2 SEMICN ; RETURNTK return LPARENT ( IDENFR change1 RPARENT ) SEMICN ; RBRACE } VOIDTK void MAINTK main LPARENT ( RPARENT ) LBRACE { PRINTFTK printf LPARENT ( STRCON Hello World RPARENT ) SEMICN ; PRINT
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值