Experiment 1
AIM: Write a program to implement the separation of
tokens from a source program.
Implementation:
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
bool isDelimiter(char ch)
{
if (ch == ' ' || ch == '+' || ch == '-' || ch == '*' ||
ch == '/' || ch == ',' || ch == ';' || ch == '>' ||
ch == '<' || ch == '=' || ch == '(' || ch == ')' ||
ch == '[' || ch == ']' || ch == '{' || ch == '}')
return (true);
return (false);
}
bool isOperator(char ch)
{
if (ch == '+' || ch == '-' || ch == '*' ||
ch == '/' || ch == ',' || ch == ';' || ch == '>' ||
ch == '<' || ch == '=' || ch == '(' || ch == ')' ||
ch == '[' || ch == ']' || ch == '{' || ch == '}')
return (true);
return (false);
}
char* subString(char* str, int left, int right)
{
int i;
char* subStr = (char*)malloc(sizeof(char) * (right - left + 2));
for (i = left; i <= right; i++)
subStr[i - left] = str[i];
subStr[right - left + 1] = '\0';
return (subStr);
}
void parse(char* str)
{
int left = 0, right = 0;
int len = strlen(str);
while (right <= len && left <= right) {
if (isDelimiter(str[right]) == false)
right++;
if (isDelimiter(str[right]) == true && left == right) {
if (isOperator(str[right]) == true)
printf("%c\n", str[right]);
right++;
left = right;
} else if (isDelimiter(str[right]) == true && left != right
|| (right == len && left != right)) {
char* subStr = subString(str, left, right - 1);
printf("%s\n", subStr);
left = right;
}
}
return;
}
int main()
{
char str[100] = "while(1){int a = 4};";
parse(str);
return (0);
}
Output:
Experiment 2
AIM: Write a program to implement lexical analysis phase
of a compiler.
Implementation:
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
bool isDelimiter(char ch)
{
if (ch == ' ' || ch == '+' || ch == '-' || ch == '*' ||
ch == '/' || ch == ',' || ch == ';' || ch == '>' ||
ch == '<' || ch == '=' || ch == '(' || ch == ')' ||
ch == '[' || ch == ']' || ch == '{' || ch == '}')
return (true);
return (false);
}
bool isOperator(char ch)
{
if (ch == '+' || ch == '-' || ch == '*' ||
ch == '/' || ch == '>' || ch == '<' ||
ch == '=')
return (true);
return (false);
}
bool validIdentifier(char* str)
{
if (str[0] == '0' || str[0] == '1' || str[0] == '2' ||
str[0] == '3' || str[0] == '4' || str[0] == '5' ||
str[0] == '6' || str[0] == '7' || str[0] == '8' ||
str[0] == '9' || isDelimiter(str[0]) == true)
return (false);
return (true);
}
bool isKeyword(char* str)
{
if (!strcmp(str, "if") || !strcmp(str, "else") ||
!strcmp(str, "while") || !strcmp(str, "do") ||
!strcmp(str, "break") ||
!strcmp(str, "continue") || !strcmp(str, "int")
|| !strcmp(str, "double") || !strcmp(str, "float")
|| !strcmp(str, "return") || !strcmp(str, "char")
|| !strcmp(str, "case") || !strcmp(str, "char")
|| !strcmp(str, "sizeof") || !strcmp(str, "long")
|| !strcmp(str, "short") || !strcmp(str, "typedef")
|| !strcmp(str, "switch") || !strcmp(str, "unsigned")
|| !strcmp(str, "void") || !strcmp(str, "static")
|| !strcmp(str, "struct") || !strcmp(str, "goto")|| !strcmp(str, "string"))
return (true);
return (false);
}
bool isInteger(char* str)
{
int i, len = strlen(str);
if (len == 0)
return (false);
for (i = 0; i < len; i++) {
if (str[i] != '0' && str[i] != '1' && str[i] != '2'
&& str[i] != '3' && str[i] != '4' && str[i] != '5'
&& str[i] != '6' && str[i] != '7' && str[i] != '8'
&& str[i] != '9' || (str[i] == '-' && i > 0))
return (false);
}
return (true);
}
bool isRealNumber(char* str)
{
int i, len = strlen(str);
bool hasDecimal = false;
if (len == 0)
return (false);
for (i = 0; i < len; i++) {
if (str[i] != '0' && str[i] != '1' && str[i] != '2'
&& str[i] != '3' && str[i] != '4' && str[i] != '5'
&& str[i] != '6' && str[i] != '7' && str[i] != '8'
&& str[i] != '9' && str[i] != '.' ||
(str[i] == '-' && i > 0))
return (false);
if (str[i] == '.')
hasDecimal = true;
}
return (hasDecimal);
}
char* subString(char* str, int left, int right)
{
int i;
char* subStr = (char*)malloc(sizeof(char) * (right - left + 2));
for (i = left; i <= right; i++)
subStr[i - left] = str[i];
subStr[right - left + 1] = '\0';
return (subStr);
}
void parse(char* str)
{
int left = 0, right = 0;
int len = strlen(str);
while (right <= len && left <= right) {
if (isDelimiter(str[right]) == false)
right++;
if (isDelimiter(str[right]) == true && left == right) {
if (isOperator(str[right]) == true)
printf("'%c' IS AN OPERATOR\n", str[right]);
else
printf("'%c' IS A DELIMITER\n", str[right]);
right++;
left = right;
} else if (isDelimiter(str[right]) == true && left != right
|| (right == len && left != right)) {
char* subStr = subString(str, left, right - 1);
if (isKeyword(subStr) == true)
printf("'%s' IS A KEYWORD\n", subStr);
else if (isInteger(subStr) == true)
printf("'%s' IS AN INTEGER\n", subStr);
else if (isRealNumber(subStr) == true)
printf("'%s' IS A REAL NUMBER\n", subStr);
else if (validIdentifier(subStr) == true
&& isDelimiter(str[right - 1]) == false)
printf("'%s' IS A VALID IDENTIFIER\n", subStr);
else if (validIdentifier(subStr) == false
&& isDelimiter(str[right - 1]) == false)
printf("'%s' IS NOT A VALID IDENTIFIER\n", subStr);
else
printf("'%s' IS A DELIMITER\n", subStr);
left = right;
}
}
return;
}
int main()
{
char str[100] = "while(1){int a = 4.6};";
parse(str);
return (0);
}
Output:
Experiment 3
AIM: Develop simple language processors like desk calculator
and assembler.
Implementation
Desk calculator
#include <iostream>
#include <sstream>
#include <stack>
#include <string>
#include <vector>
// Define a function to evaluate a given expression
double evaluateExpression(const std::string& expression) {
std::istringstream iss(expression);
std::stack<double> operandStack;
std::stack<char> operatorStack;
while (!iss.eof()) {
std::string token;
iss >> token;
if (token == "+" || token == "-" || token == "*" || token == "/") {
while (!operatorStack.empty() && operatorStack.top() != '(' && ((token == "*" || token == "/") ?
(operatorStack.top() == '*' || operatorStack.top() == '/') : true)) {
double b = operandStack.top();
operandStack.pop();
double a = operandStack.top();
operandStack.pop();
char op = operatorStack.top();
operatorStack.pop();
if (op == '+') operandStack.push(a + b);
else if (op == '-') operandStack.push(a - b);
else if (op == '*') operandStack.push(a * b);
else if (op == '/') operandStack.push(a / b);
}
operatorStack.push(token[0]);
} else if (token == "(") {
operatorStack.push('(');
} else if (token == ")") {
while (!operatorStack.empty() && operatorStack.top() != '(') {
double b = operandStack.top();
operandStack.pop();
double a = operandStack.top();
operandStack.pop();
char op = operatorStack.top();
operatorStack.pop();
2
if (op == '+') operandStack.push(a + b);
else if (op == '-') operandStack.push(a - b);
else if (op == '*') operandStack.push(a * b);
else if (op == '/') operandStack.push(a / b);
}
operatorStack.pop(); // Pop the remaining '('
} else {
double operand = stod(token);
operandStack.push(operand);
}
}
while (!operatorStack.empty()) {
double b = operandStack.top();
operandStack.pop();
double a = operandStack.top();
operandStack.pop();
char op = operatorStack.top();
operatorStack.pop();
if (op == '+') operandStack.push(a + b);
else if (op == '-') operandStack.push(a - b);
else if (op == '*') operandStack.push(a * b);
else if (op == '/') operandStack.push(a / b);
}
return operandStack.top();
}
int main() {
std::string expression;
std::cout << "Enter an arithmetic expression: ";
std::getline(std::cin, expression);
double result = evaluateExpression(expression);
std::cout << "Result: " << result << std::endl;
return 0;
}
2. ASSEMBLER
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_LENGTH 100
#define MAX_SYMBOLS 100
// Data structures to store symbols and their addresses
typedef struct {
char label[10];
int address;
} SymbolTableEntry;
3
SymbolTableEntry symbolTable[MAX_SYMBOLS];
int symbolCount = 0;
// Functions
int searchSymbolTable(char label[10]) {
for (int i = 0; i < symbolCount; i++) {
if (strcmp(symbolTable[i].label, label) == 0) {
return symbolTable[i].address;
}
}
return -1;
}
void addToSymbolTable(char label[10], int address) {
strcpy(symbolTable[symbolCount].label, label);
symbolTable[symbolCount].address = address;
symbolCount++;
}
int main() {
char line[MAX_LINE_LENGTH];
char mnemonic[10];
char label[10];
char operand[10];
int address = 0;
int machineCode = 0;
FILE *inputFile = fopen("assembly_code.txt", "r");
FILE *outputFile = fopen("machine_code.txt", "w");
if (!inputFile) {
printf("Error: Unable to open input file.\n");
return 1;
}
if (!outputFile) {
printf("Error: Unable to open output file.\n");
return 1;
}
while (fgets(line, MAX_LINE_LENGTH, inputFile)) {
sscanf(line, "%s %s %s", label, mnemonic, operand);
// First pass: Build the symbol table
if (label[0] != '\0') {
addToSymbolTable(label, address);
}
// Second pass: Translate instructions to machine code
if (strcmp(mnemonic, "ADD") == 0) {
machineCode = 0x1000;
} else if (strcmp(mnemonic, "SUB") == 0) {
machineCode = 0x2000;
} else if (strcmp(mnemonic, "LD") == 0) {
machineCode = 0x3000;
} else if (strcmp(mnemonic, "ST") == 0) {
machineCode = 0x4000;
} else if (strcmp(mnemonic, "HLT") == 0) {
4
machineCode = 0xF000;
} else {
printf("Error: Invalid mnemonic '%s'.\n", mnemonic);
return 1;
}
if (operand[0] != '\0') {
int operandValue = searchSymbolTable(operand);
if (operandValue == -1) {
printf("Error: Undefined label '%s'.\n", operand);
return 1;
}
machineCode += operandValue;
}
fprintf(outputFile, "%04X\n", machineCode);
address++;
}
fclose(inputFile);
fclose(outputFile);
printf("Assembly completed successfully.\n");
return 0;
}
RESULTS
Output:
a. Desk Calculator
5
ASSEMBLER O/P:
6
Experiment 4
AIM: Design a small high-level language.
Implementation:
Name of the Language: "MiniLang"
Features and Components:
1. Data Types:
• Integer (int): Represents whole numbers.
• Float (float): Represents numbers with decimal points.
• String (str): Represents text.
2. Variables:
• Variables are defined with the var keyword.
• Variables are dynamically typed (no need to specify data types explicitly).
3. Operators:
• Arithmetic operators: +, -, *, /, % (modulo)
• Comparison operators: ==, !=, <, >, <=, >=
• Logical operators: and, or, not
4. Control Flow:
• Conditional statements: if, else if, else
• Looping: for and while loops
5. Functions:
• Functions are defined with the func keyword.
• Support for parameters and return values.
6. Comments:
• Single-line comments using #
7
Source Code:
#include <iostream>
#include <string>
#include <stack>
#include <cctype>
#include <cstdlib>
using namespace std;
// Function to evaluate arithmetic expressions
int evaluateExpression(const string& expression) {
stack<int> values;
stack<char> operators;
for (size_t i = 0; i < expression.length(); ++i) {
if (isspace(expression[i])) {
continue; // Skip whitespace
} else if (isdigit(expression[i])) {
int value = 0;
while (i < expression.length() && isdigit(expression[i])) {
value = value * 10 + (expression[i] - '0');
++i;
}
values.push(value);
--i; // Backtrack one character
} else if (expression[i] == '+' || expression[i] == '-' || expression[i] == '*' || expression[i] == '/') {
while (!operators.empty() && (expression[i] != '+' && expression[i] != '-') && (operators.top() == '*' ||
operators.top() == '/')) {
char op = operators.top();
operators.pop();
int right = values.top();
values.pop();
int left = values.top();
values.pop();
if (op == '+') {
values.push(left + right);
} else if (op == '-') {
values.push(left - right);
} else if (op == '*') {
values.push(left * right);
} else if (op == '/') {
values.push(left / right);
}
}
operators.push(expression[i]);
} else {
cerr << "Error: Invalid character in the expression." << endl;
exit(1);
}
}
while (!operators.empty()) {
char op = operators.top();
operators.pop();
8
int right = values.top();
values.pop();
int left = values.top();
values.pop();
if (op == '+') {
values.push(left + right);
} else if (op == '-') {
values.push(left - right);
} else if (op == '*') {
values.push(left * right);
} else if (op == '/') {
values.push(left / right);
}
}
return values.top();
}
int main() {
string input;
while (true) {
cout << "Enter an arithmetic expression (or 'quit' to exit): ";
getline(cin, input);
if (input == "quit") {
break;
}
int result = evaluateExpression(input);
cout << "Result: " << result << endl;
}
return 0;
}
EXAMPLE
9
Output:
10
Experiment 5
AIM
Develop a lexical analyzer and a syntax analyzer for the same using the LEX and
YACC tools. Also implement the bookkeeper module.
Implementation
1. Lexical Analyzer(lex):
11
2 Syntax Analyzer(Yacc/bison)
%{
#include <stdio.h>
int yylex(void);
%}
%token NUMBER
%left '+' '-'
%left '*' '/'
%%
calc: expr '\n' { printf("Result: %d\n", $1);
expr: NUMBER { $$ = $1; }
| expr '+' expr { $$ = $1 + $3; }
| expr '-' expr { $$ = $1 - $3; }
| expr '*' expr { $$ = $1 * $3; }
| expr '/' expr {
if ($3 != 0) {
$$ = $1 / $3;
} else {
fprintf(stderr, "Error: Division by zero\n");
$$ = 0;
%%
int main() {
yyparse();
return 0;
}
12
Bookkeeper Module
You can create a file named bookkeeper.c with the following content:
#include <stdio.h>
void bookkeeper_module() {
printf("Bookkeeper module is working!\n");
}
Results
Compile
Input
Output
13
Experiment 6
AIM
Develop a simple calculator using LEX and YACC tools.
Implementation
Lexical Analyser for Calculator
%{
#include <stdio.h>
#include "y.tab.h"
extern int yylval;
%}
%% [ ] ;
“end” {return 0;}
[a-z] {
c = yytext[0]; yylval = c - 'a'; return(LETTER);
}
[0-9] {
c = yytext[0]; yylval = c - '0'; return(DIGIT);
}
[^a-z0-9\b] { c = yytext[0]; return(c);
}
%% 7
Parser for Calculator
%{
#include<stdio.h> int regs[26];
int base;
%}
%start list
/* %union { int a; } */
%token DIGIT LETTER
%left '|'
%left '&'
%left '+' '-'
%left '*' '/' '%'
%left UMINUS /*supplies precedence for unary minus */
%% /* beginning of rules section */ list: /*empty */
|
list stat '\n'
|
list error '\n'
{
yyerrok;
}
;
14
stat: expr
{
printf("Value of expression is %d\n",$1);
}
|
LETTER '=' expr
{
regs[$1] = $3;
}
;
expr: '(' expr ')' {
$$ = $2; }
|expr '*' expr { $$ = $1 * $3; }
|expr '/' expr { $$ = $1 / $3; }
|expr '%' expr { $$ = $1 % $3; }
|expr '+' expr { $$ = $1 + $3; }
|expr '-' expr { $$ = $1 - $3; }
|expr '&' expr { $$ = $1 & $3; }
|expr '|' expr { $$ = $1 | $3; }
|'-' expr %prec UMINUS { $$ = -$2; }
|LETTER { $$ = regs[$1]; }
|number ; number: DIGIT { $$ = $1; base = ($1==0) ? 8 : 10; }
| number DIGIT { $$ = base * $1 + $2; };
%%
main() {
printf("Enter arithmetic expressions for evaluation\nEnter end to stop.\n"); return(yyparse()); }
yyerror(s)
char *s; { fprintf(stderr, "%s\n",s); }
yywrap() {
return(1);
}
RESULTS
15
Experiment 7
AIM
Implement a program for symbol table using hashing.
Implementation
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 11
char l[10];
struct symb
{
int add;
char label[10];
}sy[11];
void search();
void main()
{
int a[MAX],num,key,i,ch;
char ans;
int create(int);
void lprob(int [],int,int);
void display(int []);
system("cls");
for(i=0;i<MAX;i++)
a[i]=0;
do
{
printf("\nEnter your choice:");
printf("\n1 - Create entry in the symbol table\n2 - Search in the symbol table\n");
scanf("%d",&ch);
switch(ch)
{
case 1:
do
{
printf("\nEnter the address:");
scanf("%d",&num);
key=create(num);
printf("Enter the label:");
scanf("%s",l);
lprob(a,key,num);
16
printf("\nContinue?\n0 for no\n1 for yes\n");
scanf("%s",ans);
}
while(ans==1);
display(a);
break;
case 2:
search();
break;
}
}while(ch<=2);
getch();
}
int create(int num)
{
int key;
key=num%11;
return key;
}
void lprob(int a[MAX],int key,int num)
{
int flag,i,count=0;
void display(int a[]);
flag=0;
if(a[key]==0)
{
a[key]=num;
sy[key].add=num;
strcpy(sy[key].label,l);
}
else
{
i=0;
while(i<MAX)
{
if(a[i]!=0)
count++;
i++;
}
if(count==MAX)
{
printf("\nHash table is full");
display(a);
getch();
exit(1);
}
for(i=key+1;i<MAX;i++)
if(a[i]==0)
{
17
a[i]=num;
flag=1;
sy[key].add=num;
strcpy(sy[key].label,l);
break;
}
for(i=0;i<key && flag==0;i++)
if(a[i]==0)
{
a[i]=num;
flag=1;
sy[key].add=num;
strcpy(sy[key].label,l);
break;
}
}
}
void display(int a[MAX])
{
FILE *fp;
int i;
fp=fopen("symbol.txt","w");
printf("\nSymbol Table:");
printf("\nHash values Address Label");
for(i=0;i<MAX;i++)
{
printf("\n%d\t %d\t %s",i,sy[i].add,sy[i].label);
fprintf(fp,"\n%d %d %s",i,sy[i].add,sy[i].label);
}
fclose(fp);
}
void search()
{
FILE *fp1;
char la[10];
int set=0,s;
int j,i;
printf("Enter the label: ");
scanf("%s",la);
fp1=fopen("symbol.txt","r");
for(i=0;i<MAX;i++)
{
fscanf(fp1,"%d%d",&j,&sy[i].add);
if(sy[i].add!=0)
fscanf(fp1,"%s",sy[i].label);
}
for(i=0;i<MAX;i++)
{
if(sy[i].add!=0)
{
18
if(strcmp(sy[i].label,la)==0)
{
set=1;
s=sy[i].add;
}
}
}
if(set==1)
printf("\nThe label '%s' is present in the symbol table at address:%d\n",la,s);
else
printf("\nThe label is not present in the symbol table\n");
}
RESULTS
19
20
21
EXPERIMENT-8
AIM
Implement a bottom-up parser using YACC tool.
Implementation
LEX file:
%{
#include<stdio.h>
#include "y.tab.h"
%}
%%
[0-9]+ {yylval.dval=atof(yytext);
return DIGIT;
}
\n|. return yytext[0];
%%
YACC file:
%{
/*This YACC specification file generates the LALR parser for the program
considered in experiment 4.*/
#include<stdio.h>
%}
%union
{
double dval;
}
%token <dval> DIGIT
%type <dval> expr
%type <dval> term
%type <dval> factor
%%
line: expr '\n' {
printf("%g\n",$1);
}
;
expr: expr '+' term {$$=$1 + $3 ;}
| term
;
term: term '*' factor {$$=$1 * $3 ;}
| factor
22
;
factor: '(' expr ')' {$$=$2 ;}
| DIGIT
;
%%
int main()
{
yyparse();
}
yyerror(char *s)
{
printf("%s",s);
}
RESULT:
$lex parser.l
$yacc –d parser.y
$cc lex.yy.c y.tab.c –ll –lm
$./a.out
9+4
15.0000
23
EXPERIMENT-9
AIM
Represent ‘C’ language using Context Free Grammar
IMPLEMENTATION
program -> declaration-list
declaration-list -> declaration
| declaration-list declaration
declaration -> var-declaration
| fun-declaration
var-declaration -> type-specifier ID ;
type-specifier -> int
| float
fun-declaration -> type-specifier ID ( params ) compound-stmt
params -> param-list
| VOID
param-list -> param
| param-list , param
param -> type-specifier ID
compound-stmt -> { local-declarations statement-list }
local-declarations -> local-declaration
| local-declarations local-declaration
local-declaration -> type-specifier ID ;
statement-list -> statement
| statement-list statement
statement -> expression-stmt
| compound-stmt
| selection-stmt
| iteration-stmt
| return-stmt
expression-stmt -> expression ;
expression -> var = expression
| simple-expression
var -> ID
simple-expression -> additive-expression relop additive-expression
| additive-expression
relop -> < | <= | > | >= | == | !=
additive-expression -> additive-expression addop term
| term
addop -> + | -
24
term -> term mulop factor
| factor
mulop -> * | /
factor -> ( expression )
| var
| call
| NUM
call -> ID ( args )
args -> arg-list
|ε
arg-list -> expression
| arg-list , expression
selection-stmt -> if ( expression ) statement
| if ( expression ) statement else statement
iteration-stmt -> while ( expression ) statement
return-stmt -> return ;
| return expression
25
EXPERIMENT-10
AIM
Add assignment statement, If then else statement and while loop to the calculator and generate the three address code for
the same
IMPLEMENTATION
import ply.yacc as yacc
# Tokens
tokens = (
'NUMBER',
'ID',
'ASSIGN',
'IF',
'THEN',
'ELSE',
'WHILE',
'PLUS',
'MINUS',
'TIMES',
'DIVIDE',
'LPAREN',
'RPAREN',
'SEMICOLON',
)
# Grammar
def p_program(p):
'''
program : statements
'''
p[0] = p[1]
def p_statements_empty(p):
'''
statements :
'''
p[0] = []
def p_statements_statement(p):
'''
statements : statements statement SEMICOLON
'''
p[0] = p[1] + [p[2]]
def p_statement_assign(p):
'''
statement : ID ASSIGN expression
'''
p[0] = ("=", p[1], p[3])
def p_statement_if(p):
'''
statement : IF expression THEN statements ELSE statements
'''
p[0] = ("if-else", p[2], p[4], p[6])
def p_statement_while(p):
'''
statement : WHILE expression statements
'''
p[0] = ("while", p[2], p[3])
26