0% found this document useful (0 votes)
4 views3 pages

C Code Lexical Analyzer Implementation

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views3 pages

C Code Lexical Analyzer Implementation

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Date:

Ex 1(a) SYMBOL TABLE

Aim:
To implement a simple lexical analyzer that processes C code, identifies data types, and
manages identifiers with memory addresses.

Algorithm:

[Link] Symbol Table: Create an empty symbol table and set the starting memory address to
1000.

[Link] Identifier: Define a function to check if an identifier already exists in the symbol table.

[Link] Identifier: Create a function to add a new identifier, update the symbol table, and adjust
the address based on data type size.

[Link] Line: Split a code line into tokens, extract data type and identifier, and clean the
identifier.

[Link] Identifiers: If the identifier is new, add it; if it exists, print its previous address.

[Link] Loop: Continuously read input until the user types "exit," processing each line.

Code:

import [Link];
import [Link];

class Symbol {
String identifier;
String datatype;
int address;

public Symbol(String identifier, String datatype, int address) {


[Link] = identifier;
[Link] = datatype;
[Link] = address;
}
}
public class LexicalAnalyzer {
static ArrayList<Symbol> symbolTable = new ArrayList<>();
static int address = 1000; // starting address

static int checkIdentifier(String id) {


for (int i = 0; i < [Link](); i++) {
if ([Link](i).[Link](id)) {
return i;
}
}
return -1;
}

static void addIdentifier(String id, String type) {


[Link](new Symbol(id, type, address));
if ([Link]("int")) {
address += 4;
} else if ([Link]("float")) {
address += 8;
} else if ([Link]("char")) {
address += 1;
}
}

static void processLine(String line) {


String[] tokens = [Link]("\\s+");
String type = tokens[0];
String id = tokens[1].replaceAll("[^a-zA-Z0-9]", "");

if ([Link]("int") || [Link]("float") || [Link]("char")) {


int index = checkIdentifier(id);
if (index == -1) {
addIdentifier(id, type);
[Link]("Identifier: " + id + ", Type: " + type + ", Address: " + (address -
([Link]("int") ? 4 : ([Link]("float") ? 8 : 1))));
} else {
[Link]("The identifier '" + id + "' has already been read before at address "
+ [Link](index).address + ".");
}
}
}

public static void main(String[] args) {


Scanner scanner = new Scanner([Link]);
String line;

[Link]("Enter C code lines (type 'exit' to quit):");

while (true) {
[Link](">> ");
line = [Link]();

if ([Link]("exit")) {
break;
}

processLine(line);
}

[Link]();
}
}

output

Enter C code lines (type 'exit' to quit):


>> int a = 6;
Identifier: a, Type: int, Address: 1000
>> int b =10;
Identifier: b, Type: int, Address: 1004
>> int c = 10;
Identifier: c, Type: int, Address: 1008
>> int a =40;
The identifier 'a' has already been read before at address 1000.
>> float a= 70.0;

Result:

Hence a simple lexical analyzer that processes C code, identifies data types, and manages
identifiers with memory addresses has been written, implemented and its output verified
successfully.

Common questions

Powered by AI

To detect and remove invalid identifiers, the analyzer could implement additional validation rules to ensure that identifiers conform to naming conventions, such as starting with a letter and not being a reserved keyword. Regular expressions and predefined lists can be used to check against invalid starting characters and keywords, enabling the analyzer to reject invalid tokens before symbol table insertion .

Improvements in user interaction could include implementing error messages for unexpected tokens or unsupported data types, offering suggestions for typographical errors, or implementing a more interactive CLI with command options to review or reset the symbol table. Furthermore, integrating a user-friendly interface with comprehensive feedback can help users better understand their input and the analyzer's corresponding output .

The symbol table acts as a data structure to store identifiers along with their corresponding data types and memory addresses. It helps the lexical analyzer track whether an identifier has been declared previously, preventing multiple declarations at differing addresses. If an identifier already exists in the symbol table, the analyzer can promptly reference its stored address .

Introducing unicode characters in identifiers can cause challenges related to character encoding and comparison operations within the symbol table. These challenges can be addressed by ensuring that the lexical analyzer handles inputs using a compatible encoding scheme like UTF-8 and validates identifiers against unicode standards to avoid unexpected behavior. Implementing an enhanced regex pattern that includes unicode character classes could help accommodate these identifiers effectively .

The lexical analyzer distinguishes identifiers by parsing the input tokens, identifying the first token as a data type, and treating the following token as an identifier. It then sanitizes the identifier by removing non-alphanumeric characters using a regular expression, allowing it to uniquely recognize and process identifiers separate from other syntax elements like operators or keywords .

To handle additional data types like 'double' or 'long', the lexical analyzer's logic for adding identifiers needs to be extended in the 'addIdentifier' method. Specifically, case checks for 'double' and 'long' should be added, with corresponding address increments; for instance, a typical increment for 'double' might be 8 bytes, and for 'long', it might be more, depending on the architecture. Adjustments to the processLine method may also be necessary to correctly parse and recognize these new data type tokens .

The lexical analyzer manages memory addresses by starting at an initial address of 1000. When a new identifier is added to the symbol table, its memory address is determined by the data type size. For an 'int', the address increases by 4; for a 'float', it increases by 8; and for a 'char', it increases by 1. As the analyzer processes each identifier, it updates the address according to these increments .

The lexical analyzer processes a line of C code by first splitting the line into tokens to extract the data type and identifier. It then cleans the identifier of non-alphanumeric characters. If the data type is 'int', 'float', or 'char', it checks if the identifier already exists in the symbol table. If it is new, it adds the identifier along with its type and address to the table. If the identifier exists, it outputs its previously assigned address .

Continuous input processing allows the lexical analyzer to dynamically accept and analyze multiple lines of C code until a termination command ('exit') is given. This design enables users to iteratively test and validate multiple identifiers in one execution session, enhancing the analyzer's usability and flexibility by not limiting it to predefined input quantities .

If a lexical analyzer fails to check for existing identifiers, it could result in multiple allocations of memory addresses for the same identifier. This redundancy may lead to incorrect referencing in program execution, as operations might not target the correct memory location, potentially causing logical errors or unexpected behavior in the output .

You might also like