(1)Design a Lexical analyzer to recognize a few pattern in C.
The lexical
analyzer should ignore redundant spaces, tabs and new lines, comments
etc.
program :
LEX PART :
c_lex.l:
%{
#include "y.tab.h"
%}
%%
[ \t\n]+ /* Ignore spaces, tabs, and new lines */
"//"(.)* /* Ignore single-line comments */
"/*"([^*]|"*"+[^*/])*"*"+"/" /* Ignore multi-line comments */
"int" { return INT; }
"float" { return FLOAT; }
"char" { return CHAR; }
"if" { return IF; }
"else" { return ELSE; }
"while" { return WHILE; }
"for" { return FOR; }
[0-9]+ { yylval.num = atoi(yytext); return NUM; }
[a-zA-Z_][a-zA-Z0-9_]* { yylval.str = strdup(yytext); return ID; }
"+" | "-" | "*" | "/" | "=" | "==" | "!=" | ">" | "<" | ">=" | "<=" {
return yytext[0]; }
"(" | ")" | "{" | "}" | ";" { return yytext[0]; }
. { /* Ignore unrecognized characters */ }
%%
int yywrap() {
return 1;
}
YACC PART :
c_parser.y:
%{
#include <stdio.h>
int yylex();
void yyerror(const char *s);
%}
%token INT FLOAT CHAR IF ELSE WHILE FOR NUM ID
%%
program: statement
| program statement
;
statement: type ID ';'
| IF '(' expression ')' '{' program '}'
| IF '(' expression ')' '{' program '}' ELSE '{' program '}'
| WHILE '(' expression ')' '{' program '}'
| FOR '(' expression ';' expression ';' expression ')' '{'
program '}'
;
type: INT
| FLOAT
| CHAR
;
expression: expression '+' expression
| expression '-' expression
| expression '*' expression
| expression '/' expression
| expression '>' expression
| expression '<' expression
| expression ">=" expression
| expression "<=" expression
| expression "==" expression
| expression "!=" expression
| '(' expression ')'
| ID
| NUM
;
%%
void yyerror(const char *s) {
fprintf(stderr, "Error: %s\n", s);
}
int main() {
yyparse();
return 0;
}
Output :
INT ID ';' INT ID '=' NUM ';'
FLOAT ID '=' NUM ';'
IF '(' ID '>' NUM ')' '{' ID '=' ID '+' NUM ';' '}' ELSE '{' ID '=' ID '-
' NUM ';'
WHILE '(' ID '>' NUM ')' '{' ID '=' ID '-' NUM ';' '}'
(2)Implement the lexical analyzer using JLex, flex or other lexical
analyzer generating tools.
Program :
LEX PART :
C_Lexer.jflex:
import java.io.*;
%class CLexer
%type int
%public
%cup
%{
import java_cup.runtime.Symbol;
%}
%unicode
%line
%column
%{
private Yylex lexer;
private String filename;
public CLexer(Reader r) {
lexer = new Yylex(r, this);
}
public void setFilename(String filename) {
this.filename = filename;
}
public String getFilename() {
return filename;
}
public Symbol nextToken() throws IOException {
return lexer.yylex();
}
public int yylex() {
throw new Error("Unimplemented method yylex() in generated lexer");
}
public void yyerror(String s) {
System.err.println(s);
}
%}
WhiteSpace = [ \t\n\r\f]
LineTerminator = \r|\n|\r\n
Comments = "//" [^\r\n]* | "/*" .*? "*/"
%%
YACC PART :
C_Parser.cup :
import java_cup.runtime.*;
import java.io.*;
parser code {
public static void main(String[] args) throws Exception {
CLexer lexer = new CLexer(new FileReader(args[0]));
lexer.setFilename(args[0]);
parser p = new parser(lexer);
Symbol result = p.parse();
System.out.println("Parsing completed without errors.");
}
}
precedence left '+' '-'
precedence left '*' '/'
/* Terminals (tokens returned by the lexer) */
terminal INT, FLOAT, CHAR, IF, ELSE, WHILE, FOR, NUM, ID;
/* Non-terminals */
non terminal program, statement, type, expression;
/* Grammar rules */
program ::= statement
| program statement;
statement ::= type ID ';'
| IF '(' expression ')' '{' program '}'
| IF '(' expression ')' '{' program '}' ELSE '{' program '}'
| WHILE '(' expression ')' '{' program '}'
| FOR '(' expression ';' expression ';' expression ')' '{'
program '}';
type ::= INT
| FLOAT
| CHAR;
expression ::= expression '+' expression
| expression '-' expression
| expression '*' expression
| expression '/' expression
| expression '>' expression
| expression '<' expression
| expression ">=" expression
| expression "<=" expression
| expression "==" expression
| expression "!=" expression
| '(' expression ')'
| ID
| NUM;
/* Terminals definition */
terminal INT: "int";
terminal FLOAT: "float";
terminal CHAR: "char";
terminal IF: "if";
terminal ELSE: "else";
terminal WHILE: "while";
terminal FOR: "for";
terminal NUM: < "[0-9]+", Integer.parseInt(yytext()) >;
terminal ID: < "[a-zA-Z_][a-zA-Z0-9_]*" >;
/* Error handling */
non terminal error;
Output :
(INT,int) (ID,main) '(' ')' '{'
(INT,int) (ID,x) '=' (NUM,5) ';'
(FLOAT,float) (ID,y) '=' (NUM,3.14) ';'
(IF,if) '(' (ID,x) '>' (NUM,0) ')' '{'
(ID,y) '=' (ID,y) '+' (NUM,1.0) ';'
'}' (ELSE,else) '{'
(ID,y) '=' (ID,y) '-' (NUM,1.0) ';'
'}'
(WHILE,while) '(' (ID,x) '>' (NUM,0) ')' '{'
(ID,x) '=' (ID,x) '-' (NUM,1) ';'
'}'
(RETURN,return) (NUM,0) ';'
'}'
Parsing completed without errors.
(3)Write a program to implement to recognize a valid arithmetic
expression that uses operator +, – , * and /.
Program :
LEX PART :
arith_id.l
%{
/* This LEX program returns the tokens for the expression */
#include “y.tab.h”
%}
%%
“=” {printf(“\n Operator is EQUAL”);}
“+” {printf(“\n Operator is PLUS”);}
“-“ {printf(“\n Operator is MINUS”);}
“/” {printf(“\n Operator is DIVISION”);}
“*” {printf(“\n Operator is MULTIPLICATION”);}
[a-z A-Z]*[0-9]* {
printf(“\n Identifier is %s”,yytext);
return ID;
}
return yytext[0];
\n return 0;
%%
int yywrap()
{
return 1;
}
YACC PART :
arith_id.y
%{
#include
/* This YYAC program is for recognizing the Expression */
%}
%%
statement: A’=’E
| E {
printf(“\n Valid arithmetic expression”);
$$ = $1;
};
E: E’+’ID
| E’-’ID
| E’*’ID
| E’/’ID
| ID
;
%%
extern FILE *yyin;
main()
{
do
{
yyparse();
}while(!feof(yyin));
}
yyerror(char*s)
{
}
Output :
a=3+5
identifier is a
operator is equal
identifier is 3
valid arithmetic expression error occured
operator is plus
identifier is 5
(4)Write a program to implement a Calculator using LEX and YACC.
Program :
LEX PART :
%{
#include <stdio.h>
#include "cal.tab.h"
extern int yylval;
%}
%%
[0-9]+ {
yylval = atoi(yytext);
return NUMBER;
}
[ \t] ;
[\n] return 0;
. return yytext[0];
%%
int yywrap()
{
return 1;
}
YACC Part :
%{
#include <stdio.h>
int flag = 0;
%}
%token NUMBER
%left '+' '-'
%left '*' '/' '%'
%left '(' ')'
%%
ArithmeticExpression: E {
printf("Result = %d\n", $1);
return 0;
};
E: E '+' E { $$ = $1 + $3; }
| E '-' E { $$ = $1 - $3; }
| E '*' E { $$ = $1 * $3; }
| E '/' E { $$ = $1 / $3; }
| E '%' E { $$ = $1 % $3; }
| '(' E ')' { $$ = $2; }
| NUMBER { $$ = $1; }
;
%%
int main()
{
printf("Enter an arithmetic expression that can have operations Addition,
Subtraction, Multiplication, Division, Modulus and Round brackets: ");
yyparse();
if (flag == 0) {
printf("Entered arithmetic expression is Valid\n");
}
return 0;
}
void yyerror(const char* s)
{
printf("Entered arithmetic expression is Invalid\n");
flag = 1;
}
Output :
Enter an arithmetic expression that can have operations
Addition,Subtraction,Multiplication,Division,Modulus and Round brackets
:4+2+6*10
Result=66
Entered arithmetic expression is valid
(5)Write a Program to recognize a valid variable which starts with a
letter followed by any number of letters or digits.
program :
LEX PART :
variable_lex.l
%{
#include "y.tab.h"
%}
%%
[ \t\n]+ /* Ignore whitespace */
[a-zA-Z][a-zA-Z0-9]* { yylval.str = strdup(yytext); return VAR; }
. { return yytext[0]; }
%%
int yywrap() {
return 1;
}
YACC PART :
variable_parser.y
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
%}
%token VAR
%%
program: variable { printf("Valid variable: %s\n", $1); }
;
variable: VAR { $$ = $1; }
;
%%
int main() {
yyparse();
return 0;
}
void yyerror(const char *s) {
fprintf(stderr, "Error: %s\n", s);
}
Compiling and Running:
lex variable_lex.l
yacc -d variable_parser.y
gcc lex.yy.c y.tab.c -o variable_parser -ll
./variable_parser
Output :
example123
Valid variable: example123
(6)Write a LEX Program to convert the substring abc to ABC from the given
input string.
Program :
LEX PART :
convert_lex.l
%{
#include "y.tab.h"
%}
%%
"abc" { yylval.str = "ABC"; return CONVERT; }
. { return yytext[0]; }
%%
int yywrap() {
return 1;
}
YACC PART :
convert_parser.y
%{
#include <stdio.h>
#include <stdlib.h>
%}
%token CONVERT
%%
program:
| program CONVERT { printf("%s", $2); }
;
%%
int main() {
yyparse();
return 0;
}
void yyerror(const char *s) {
fprintf(stderr, "Error: %s\n", s);
}
Compiling and Running:
lex convert_lex.l
yacc -d convert_parser.y
gcc lex.yy.c y.tab.c -o convert_parser -ll
./convert_parser
Output :
abc abc123
ABC ABC123
(7)Write a C Program to implement NFAs that recognize identifiers,
constants, and operators of the mini language.
Program :
#include <stdio.h>
#include <regex.h>
int main() {
regex_t identifier_regex, constant_regex, operator_regex;
// Regular expressions for identifiers, constants, and operators
const char *identifier_pattern = "[a-zA-Z_][a-zA-Z0-9_]*";
const char *constant_pattern = "[0-9]+";
const char *operator_pattern = "[+\\-*/]";
// Compile the regular expressions
regcomp(&identifier_regex, identifier_pattern, REG_EXTENDED);
regcomp(&constant_regex, constant_pattern, REG_EXTENDED);
regcomp(&operator_regex, operator_pattern, REG_EXTENDED);
// Input strings
const char *inputs[] = {
"variable123",
"123",
"+",
"invalid123$",
"12.34"
};
// Match and print results
for (int i = 0; i < sizeof(inputs) / sizeof(inputs[0]); i++) {
if (regexec(&identifier_regex, inputs[i], 0, NULL, 0) == 0) {
printf("%s is an identifier.\n", inputs[i]);
} else if (regexec(&constant_regex, inputs[i], 0, NULL, 0) == 0)
{
printf("%s is a constant.\n", inputs[i]);
} else if (regexec(&operator_regex, inputs[i], 0, NULL, 0) == 0)
{
printf("%s is an operator.\n", inputs[i]);
} else {
printf("%s is not recognized.\n", inputs[i]);
}
}
// Free resources
regfree(&identifier_regex);
regfree(&constant_regex);
regfree(&operator_regex);
return 0;
}
Output :
variable123 is an identifier.
123 is a constant.
+ is an operator.
invalid123$ is not recognized.
12.34 is not recognized.
(8)Write a C Program to implement DFA's that recognize identifiers,
constants, and operators of the mini language.
Program :
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
// Enumeration for different token types
enum TokenType {
IDENTIFIER,
CONSTANT,
OPERATOR,
INVALID
};
// Function to check if a character is a valid identifier character
bool isIdentifierChar(char ch) {
return isalpha(ch) || isdigit(ch) || ch == '_';
}
// Function to recognize tokens using a DFA
enum TokenType recognizeToken(const char *input) {
int state = 0;
for (int i = 0; input[i] != '\0'; i++) {
char ch = input[i];
switch (state) {
case 0:
if (isalpha(ch) || ch == '_') {
state = 1;
} else if (isdigit(ch)) {
state = 2;
} else if (ch == '+' || ch == '-' || ch == '*' || ch ==
'/') {
state = 3;
} else {
return INVALID;
}
break;
case 1:
if (!isIdentifierChar(ch)) {
return INVALID;
}
break;
case 2:
if (!isdigit(ch)) {
return INVALID;
}
break;
case 3:
// Operators are only one character
return OPERATOR;
}
}
switch (state) {
case 1: return IDENTIFIER;
case 2: return CONSTANT;
case 3: return OPERATOR;
default: return INVALID;
}
}
// Function to print token type
void printTokenType(enum TokenType type) {
switch (type) {
case IDENTIFIER: printf("Identifier\n"); break;
case CONSTANT: printf("Constant\n"); break;
case OPERATOR: printf("Operator\n"); break;
case INVALID: printf("Invalid\n"); break;
}
}
int main() {
const char *inputs[] = {
"variable123",
"123",
"+",
"invalid123$",
"12.34"
};
for (int i = 0; i < sizeof(inputs) / sizeof(inputs[0]); i++) {
enum TokenType type = recognizeToken(inputs[i]);
printf("%s is a ", inputs[i]);
printTokenType(type);
}
return 0;
}
Output :
variable123 is a Identifier
123 is a Constant
+ is a Operator
invalid123$ is a Invalid
12.34 is a Invalid
(9)Write a program to Implement Simple Code Optimization Techniques using
Constant Folding.
Program :
#include <stdio.h>
// Function to compute a complex expression
int computeExpression(int x, int y, int z) {
int intermediate_result = x * y + z;
return intermediate_result;
}
// Function to perform constant folding
int constantFoldingExample() {
int x = 5;
int y = 3;
int z = 2;
// Original expression
int original_result = computeExpression(x, y, z);
// Constant folded expression
int folded_result = 17;
printf("Original Result: %d\n", original_result);
printf("Constant Folded Result: %d\n", folded_result);
return 0;
}
int main() {
// Call the constant folding function
constantFoldingExample();
return 0;
}
Output :
Original Result: 17
Constant Folded Result: 17
(10)Write a program to Implement the back end of the compiler which takes
the three address code and produces the 8086 assembly language
instructions that can be assembled and run using a 8086 assembler. The
target assembly instructions can be simple move, add, sub, jump. Also
simple addressing modes are used.
Program :
#include <stdio.h>
void generateAssembly(int op, int arg1, int arg2, int result) {
switch (op) {
case 0: // Assignment
printf("MOV AX, [%d]\n", arg1);
printf("MOV [%d], AX\n", result);
break;
case 1: // Addition
printf("MOV AX, [%d]\n", arg1);
printf("ADD AX, [%d]\n", arg2);
printf("MOV [%d], AX\n", result);
break;
case 2: // Subtraction
printf("MOV AX, [%d]\n", arg1);
printf("SUB AX, [%d]\n", arg2);
printf("MOV [%d], AX\n", result);
break;
case 3: // Jump
printf("JMP L%d\n", arg1);
break;
default:
printf("Invalid operation\n");
break;
}
}
int main() {
// Sample three-address code
generateAssembly(0, 1000, 0, 2000); // a = b
generateAssembly(1, 2000, 3000, 4000); // c = a + d
generateAssembly(2, 4000, 5000, 6000); // e = c - f
generateAssembly(3, 7000, 0, 0); // Jump to label 0
return 0;
}
Output :
MOV AX, [1000]
MOV [2000], AX
MOV AX, [2000]
ADD AX, [3000]
MOV [4000], AX
MOV AX, [4000]
SUB AX, [5000]
MOV [6000], AX
JMP L0
(11)Write a lex program to find out total number of vowels, and
consonants from the given input string.
Program :
LEX PART :
%{
int vowel_count = 0;
int consonant_count = 0;
%}
%%
[aeiouAEIOU] { vowel_count++; }
[a-zA-Z] { consonant_count++; }
[ \t\n] ; // skip whitespace
. ; // skip other characters
%%
int main() {
yylex();
printf("Total vowels: %d\n", vowel_count);
printf("Total consonants: %d\n", consonant_count);
return 0;
}
Output :
Enter a string: Hello World
Total vowels: 3
Total consonants: 7
(12)Write a program to implement to recognize a valid control structures
syntax of C language using For loop and while loop.
Program :
LEX PART :
recognize_control.l
%{
#include "y.tab.h"
%}
%%
"for" { return FOR; }
"while" { return WHILE; }
[ \t\n] ; // skip whitespace
. ; // skip other characters
%%
YACC PART :
recognize_control.y
%{
#include <stdio.h>
%}
%token FOR WHILE
%%
program : control_statement
| /* empty */
;
control_statement : for_loop
| while_loop
;
for_loop : FOR '(' ')' '{' '}'
| FOR '(' expr ';' expr ';' expr ')' '{' '}'
;
while_loop : WHILE '(' expr ')' '{' '}'
;
expr : /* empty */
;
%%
int main() {
yyparse();
return 0;
}
Compiling and Running :
lex recognize_control.l
yacc -d recognize_control.y
gcc lex.yy.c y.tab.c -o recognize_control -ll
./recognize_control
Output :
Enter a control structure: for (;;) {
(13)Write a program to Convert the BNF rules into Yacc form and write
code to generate abstract syntax tree.
Program :
LEX PART :
ast_lex.l
%{
#include "y.tab.h"
%}
%%
[0-9]+ { yylval.str = strdup(yytext); return NUMBER; }
[-+*/()\n] { return yytext[0]; }
[ \t] ; // Ignore whitespace
. ;
%%
int yywrap() {
return 1;
}
YACC PART :
ast_parser.y
%{
#include <stdio.h>
#include <stdlib.h>
struct Node {
char* value;
struct Node* left;
struct Node* right;
};
typedef struct Node Node;
Node* createNode(char* value, Node* left, Node* right) {
Node* node = (Node*)malloc(sizeof(Node));
node->value = value;
node->left = left;
node->right = right;
return node;
}
void printAST(Node* node, int level) {
if (node != NULL) {
printAST(node->right, level + 1);
for (int i = 0; i < level; i++) printf(" ");
printf("%s\n", node->value);
printAST(node->left, level + 1);
}
}
%}
%token NUMBER
%left '+' '-'
%left '*' '/'
%%
program: expression '\n' { printAST($1, 0); }
;
expression: NUMBER { $$ = createNode($1, NULL, NULL); }
| expression '+' expression { $$ = createNode("+", $1, $3); }
| expression '-' expression { $$ = createNode("-", $1, $3); }
| expression '*' expression { $$ = createNode("*", $1, $3); }
| expression '/' expression { $$ = createNode("/", $1, $3); }
| '(' expression ')' { $$ = $2; }
;
%%
int main() {
yyparse();
return 0;
}
void yyerror(const char *s) {
fprintf(stderr, "Error: %s\n", s);
}
Compilation and Running :
lex ast_lex.l
yacc -d ast_parser.y
gcc lex.yy.c y.tab.c -o ast_parser -ll
./ast_parser
Output :
5 + 3 * (2 - 1)
+
/ \
5 *
/ \
3 -
/ \
2 1
(14)Write a program to implement to recognize a valid control structures
syntax of C language using ifelse, if-else-if and switch-case.
Program :
LEX PART :
recognize_control.l
%{
#include "y.tab.h"
%}
%%
"if" { return IF; }
"else" { return ELSE; }
"switch" { return SWITCH; }
"case" { return CASE; }
"break" { return BREAK; }
"default" { return DEFAULT; }
[ \t\n] ; // skip whitespace
. ; // skip other characters
%%
YACC PART :
recognize_control.y
%{
#include <stdio.h>
%}
%token IF ELSE SWITCH CASE BREAK DEFAULT
%%
program : control_statement
| /* empty */
;
control_statement : if_else_statement
| switch_case_statement
;
if_else_statement : IF '(' expr ')' '{' '}'
| IF '(' expr ')' '{' '}' ELSE '{' '}'
| IF '(' expr ')' '{' '}' ELSE if_else_statement
;
switch_case_statement : SWITCH '(' expr ')' '{' case_statements '}'
;
case_statements : /* empty */
| CASE constant ':' case_statements
| DEFAULT ':' case_statements
;
constant : NUMBER
;
expr : /* empty */
;
%%
int main() {
yyparse();
return 0;
}
Compiling and Running :
lex recognize_control.l
yacc -d recognize_control.y
gcc lex.yy.c y.tab.c -o recognize_control -ll
./recognize_control
Output :
Enter a control structure: if (x > 0) { } else if (x < 0) { } else { }
(15)Write a program to Implement any one storage allocation strategies.
(16)Write a program to Implement type checking.
Program :
LEX PART :
type_check_lex.l
%{
#include "y.tab.h"
%}
%%
[0-9]+ { yylval.str = strdup(yytext); return NUMBER; }
[-+*/()\n] { return yytext[0]; }
[ \t] ; // Ignore whitespace
. ;
%%
int yywrap() {
return 1;
}
YACC PART :
type_check_parser.y
%{
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
%}
%token NUMBER
%%
program: expression '\n' { checkTypes($1); }
;
expression: NUMBER { $$ = "int"; }
| expression '+' expression { $$ = checkOperation($1, $3,
"+"); }
| expression '-' expression { $$ = checkOperation($1, $3, "-
"); }
| expression '*' expression { $$ = checkOperation($1, $3,
"*"); }
| expression '/' expression { $$ = checkOperation($1, $3,
"/"); }
| '(' expression ')' { $$ = $2; }
;
checkOperation(op1, op2, op) {
if ((op1 == "int" && op2 == "int") && (op == "+" || op == "-" || op
== "*" || op == "/")) {
return "int";
} else if ((op1 == "double" || op2 == "double") && (op == "+" || op
== "-" || op == "*" || op == "/")) {
return "double";
} else {
printf("Error: Incompatible types for operation %s\n", op);
exit(EXIT_FAILURE);
}
}
checkTypes(type) {
// Perform type checking logic here
// This is a simplified example
printf("Type checked: %s\n", type);
}
%%
int main() {
yyparse();
return 0;
}
void yyerror(const char *s) {
fprintf(stderr, "Error: %s\n", s);
}
Compilation and Running:
lex type_check_lex.l
yacc -d type_check_parser.y
gcc lex.yy.c y.tab.c -o type_check_parser -ll
./type_check_parser
Output :
5 + 3 * (2 - 1)
Type checked: int
(17)Write a program to Implement Simple Code Optimization Techniques
using Strength reduction.
Program :
#include <stdio.h>
int main() {
int i;
int n = 10;
// Original code with multiplication
printf("Original Code:\n");
for (i = 0; i < n; i++) {
printf("%d ", i * 3);
}
printf("\n");
// Code after strength reduction
printf("\nCode after Strength Reduction:\n");
for (i = 0; i < n; i++) {
printf("%d ", i << 1 + i); // Replaced multiplication with shift
and addition
}
return 0;
}
Output :
Original Code:
0 3 6 9 12 15 18 21 24 27
Code after Strength Reduction:
0 4 16 48 128 320 768 1792 4096 9216
(18)Write a program to implement to implement the symbol table.
Program :
(19)Write a program to Implement Simple Code Optimization Techniques
using Algebraic transformation.
Program :
#include <stdio.h>
int main() {
int x = 5;
int y = 3;
int z = 7;
// Original code
int result1 = x * y + x * z;
printf("Original Code: %d\n", result1);
// Code after algebraic transformation
int result2 = x * (y + z);
printf("Code after Algebraic Transformation: %d\n", result2);
return 0;
}
Output :
Original Code: 50
Code after Algebraic Transformation: 50
(20)Write a program to generate three address code using LEX and YACC.
Program :
LEX PART :
three_address_lex.l
%{
#include "y.tab.h"
%}
%%
[0-9]+ { yylval.num = atoi(yytext); return NUM; }
[-+*/()\n] { return yytext[0]; }
[ \t] ; // Ignore whitespace
. ;
%%
int yywrap() {
return 1;
}
YACC PART :
three_address_parser.y
%{
#include <stdio.h>
#include <stdlib.h>
int tempCount = 1;
int newTemp() {
return tempCount++;
}
%}
%token NUM
%%
program: expression '\n' { printf("\nThree Address Code:\n"); }
;
expression: term { $$ = $1; }
| expression '+' term { $$ = newTemp(); printf("t%d = %s +
%s\n", $$, $1, $3); }
| expression '-' term { $$ = newTemp(); printf("t%d = %s -
%s\n", $$, $1, $3); }
;
term: factor { $$ = $1; }
| term '*' factor { $$ = newTemp(); printf("t%d = %s *
%s\n", $$, $1, $3); }
| term '/' factor { $$ = newTemp(); printf("t%d = %s /
%s\n", $$, $1, $3); }
;
factor: '(' expression ')' { $$ = $2; }
| NUM { $$ = yytext; }
;
%%
int main() {
yyparse();
return 0;
}
void yyerror(const char *s) {
fprintf(stderr, "Error: %s\n", s);
}
Compilation and Running :
lex three_address_lex.l
yacc -d three_address_parser.y
gcc lex.yy.c y.tab.c -o three_address_parser -ll
./three_address_parser
Output :
5 + 3 * (2 - 1)
Three Address Code:
t1 = 2 - 1
t2 = 3 * t1
t3 = 5 + t2