如何根据C代码创建转换图

时间:2016-10-02 19:59:34

标签: c compiler-construction transition diagram lexical

我必须为词法分析器创建标识符和数字的转换图。

代码如下:

/* recursive factorial function */
int fact (int x )
{ 
   if (x>1)
      return x * fact (x-1); 
   else 
      return 1; 
} 

void main (void)
{
    int x;    
    x = read(); 
    if (x > 0) write (fact (x)); 
} 

我对如何创建此图表感到有点迷茫。任何人都可以指出我正确的方向或包括可以帮助我完成这项任务的资源吗?

2 个答案:

答案 0 :(得分:0)

词法分析器以null或初始状态开始。它击中了" i"。所以它知道它必须有关键字或标识符。它击中了' n'并且' t'并将它们添加到令牌。它击中了空间。所以它知道令牌的结尾,即" int",一个关键字。现在它击中了' f。同样的故事,但令牌是"事实",这不是关键字,所以它是一个标识符。现在'(' - 这是一个开括号括号。所以它继续。

当它出现' /'这可能是一个除法令牌或评论的开头,实际上它是评论的开头。所以它现在进入评论状态,直到达到* /。

除了那里有一些整数文字标记外,没有什么显着不同。为了方便你,没有任何字符串。 main是一个特殊情况,取决于词法分析器的编写方式,它可以被视为关键字或普通标识符。

答案 1 :(得分:0)

Malcolm McLean告诉你如何在实际代码中完成它,但我认为你需要一个有限状态机的理论方法。

首先进行库存检查:需要什么,我们有什么符号等等。示例代码中的EBNF:

space = ? US-ASCII character 32 ?;
zero = '0';
digit = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
character = 'a' | 'A' | 'b' | 'B' ... 'z' | 'Z';

(* a single digit might be zero but a number must not start with a zero (no octals) *)
integer = (digit|zero) | ( digit,{(digit|zero)});
(* identifier must start with a character *)
identifier = character,{ (digit | character) };
(* the keywords from the example, feel free to add more *)
keywords = "if" | "else" | "return" | "int" | "void";

(* TODO: line-end, tabs, etc. *)
delimiter = space, {space};

braceleft = '{';
braceright = '}';
parenleft = '(';
parenright = ')';

equal = '=';
greater = '>';
smaller = '<';

minus = '-';
product = '*';

semicolon = ';'

end = ? byte denoting EOF (end of file) ?;

现在制作转换表。从状态START开始。 START只是一个开始状态,没什么特别的,没什么可做的,但我们需要从某个地方开始。所以从那里我们可以得到任何上述字符。实际上,在每个州之后总是如此,所以我们可以做C&amp; P;

START
      zero        ->  ZERO
      digit       ->  INTEGER
      character   ->  IDENTIFIER
      space       ->  START
      braceleft   ->  BRACES
      braceright  ->  BRACES
      parenleft   ->  PARENTHESES
      parenright  ->  PARENTHESES
      equal       ->  COMPARING
      greater     ->  COMPARING
      smaller     ->  COMPARING
      minus       ->  ARITHMETIC
      product     ->  ARITHMETIC
      semicolon   ->  START
      end         ->  END

ZERO
      zero        ->  ERROR (well...)
      digit       ->  ERROR
      character   ->  ERROR
      space       ->  START
      braceleft   ->  BRACES
      braceright  ->  BRACES
      parenleft   ->  PARENTHESES
      parenright  ->  PARENTHESES
      equal       ->  COMPARING
      greater     ->  COMPARING
      smaller     ->  COMPARING
      minus       ->  ARITHMETIC
      product     ->  ARITHMETIC
      semicolon   ->  START
      end         ->  END

INTEGER
      zero        ->  INTEGER
      digit       ->  INTEGER
      character   ->  ERROR
      space       ->  START
      braceleft   ->  BRACES
      braceright  ->  BRACES
      parenleft   ->  PARENTHESES
      parenright  ->  PARENTHESES
      equal       ->  COMPARING
      greater     ->  COMPARING
      smaller     ->  COMPARING
      minus       ->  ARITHMETIC
      product     ->  ARITHMETIC
      semicolon   ->  START
      end         ->  END

状态IDENTIFIER表示我们已经有了一个角色,所以

IDENTIFIER
      zero        ->  IDENTIFIER
      digit       ->  IDENTIFIER
      character   ->  IDENTIFIER
      space       ->  START
      braceleft   ->  BRACES
      braceright  ->  BRACES
      parenleft   ->  PARENTHESES
      parenright  ->  PARENTHESES
      equal       ->  COMPARING
      greater     ->  COMPARING
      smaller     ->  COMPARING
      minus       ->  ARITHMETIC
      product     ->  ARITHMETIC
      semicolon   ->  START
      end         ->  END

除状态ERROR

之外,状态ERROR之后没有任何内容
ERROR -> ERROR

除状态END

之外,状态ERROR之后没有任何内容
END -> ERROR



ARITHMETIC
      zero        ->  ZERO
      digit       ->  INTEGER
      character   ->  IDENTIFIER
      space       ->  START
      braceleft   ->  BRACES
      braceright  ->  BRACES
      parenleft   ->  PARENTHESES
      parenright  ->  PARENTHESES
      equal       ->  COMPARING
      greater     ->  COMPARING
      smaller     ->  COMPARING
      minus       ->  ARITHMETIC
      product     ->  ARITHMETIC
      semicolon   ->  START
      end         ->  END

将计数和余额检查留给解析器

BRACES -> START
PARENTHESES -> START

COMPARING
      zero        ->  ZERO
      digit       ->  INTEGER
      character   ->  IDENTIFIER
      space       ->  START
      braceleft   ->  BRACES
      braceright  ->  BRACES
      parenleft   ->  PARENTHESES
      parenright  ->  PARENTHESES
      equal       ->  ERROR (only check for single characters here, no ">=" or similar)
      greater     ->  ERROR
      smaller     ->  ERROR
      minus       ->  ERROR
      product     ->  ERROR
      semicolon   ->  ERROR
      end         ->  ERROR

希望我没有实现任何严重错误,剩下的唯一问题是空格和关键字。 使用示例&#34; if&#34;:

首次出现角色

      character   ->  KEYWORDS

KEYWORDS
      'i' -> IF
      'r' -> RETURN
      ...
      any other character (exc. parens etc.) -> IDENTIFIER

IF
      'f' -> IT_IS_IF
      ...
      any other character (exc. parens etc.) -> IDENTIFIER

IT_IS_IF
      '(' -> START
      ')' -> ERROR
      '=' -> ERROR
      ...
      digit or character -> IDENTIFIER 

当然,您可以使用快捷方式进行操作,并将每个关键字设为单个符号,否则会非常繁琐。我猜是允许一点作弊?

再次出现在角色的第一次出现

      character   ->  KEYWORDS

KEYWORDS
      if_symbol -> IF
      else_symbol -> ELSE
      return_symbol -> RETURN
      ...
      digit or character -> IDENTIFIER 

IF
      '(' -> PARENTHESES
      ')' -> ERROR
      '=' -> ERROR
      ...

那么,可以你只是跳过所有的空格?像

这样的结构
return x;

一样合法
returnx;

因此,一旦你有一个完整的关键字,它后面跟一个空格(或一个分号或大括号或允许某个重新分隔的单词之后的任何符号)或后跟一个字符/数字,使其成为一个标识符,或者接着是不允许的事情。其余的可以,而且应该留给解析器。

或者你采取了第一个方法:一旦你有一个关键词,你就回去开始,所以returnx;会被视为RETURN IDENTIFIER SEMICOLON。但这会减少可能的标识符的数量,例如:ifitsone将是IF ERROR,这很可能会导致你的bug列表中有很多愤怒的条目。

通过上述所有信息,您可以构建表格。如果我们将行设置为状态,将列设置为符号

             zero        digit     character  space  braceleft  braceright  parenleft    ...
START        ZERO       INTEGER   IDENTIFIER  START    BRACES     BRACES   PARENTHESES   ...
ZERO         ERROR       ERROR     ERROR      START    BRACES     BRACES   PARENTHESES   ...
INTEGER      INTEGER    INTEGER    ERROR      START    BRACES     BRACES   PARENTHESES   ...
IDENTIFIER  IDENTIFIER IDENTIFIER IDENTIFIER  START    BRACES     BRACES   PARENTHESES   ...
  ... 

注意:上述所有内容都非常简化,可能包含错误!但基本上它是如何运作的,它不是 复杂,它只是有一些你需要学习的花哨的名字。

刚刚看到Malcolm McLean的回答被认为是可以接受的,所以......