π§Ύ C1 Language Parser – Updated
Documentation with Line-by-Line
Explanation
π Line-by-line Code Explanation
import re
β Purpose: Imports the re module which allows the use of regular expressions for pattern
matching and parsing code.
type_keywords = {'int', 'float', 'char', 'double', 'long', 'short', 'string'}
all_keywords = type_keywords.union({'main', 'function'})
β Purpose:
ββ type_keywords defines the allowed data types in the language.β
ββ all_keywords extends this set to include reserved words such as main and
function.β
decl_pattern =
r'^(int|float|char|double|long|short|string)\s+[a-zA-Z_][a-zA-Z0-9_]*(\[\d+\])?(\s*=\s*[^;]+)?;$'
β Purpose: Matches valid variable declarations, optionally including array brackets and
initialization.
assign_pattern = r'^[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*[^;]+;$'
β Purpose: Matches valid assignment statements like x = 10;.
main_pattern = r'^main\s*\(\s*\)\s*\{$'
function_pattern = r'^function\s+[a-zA-Z_][a-zA-Z0-9_]*\s*\(\s*\)\s*\{$'
dictionary_pattern = r'^[a-zA-Z_][a-zA-Z0-9_]*\s*\{$'
β Purpose:
ββ main_pattern: Matches main() block opening.β
ββ function_pattern: Matches function functionName() { pattern.β
ββ dictionary_pattern: Matches blocks like blockName {.β
PUNCTUATORS = {';', '{', '}', '(', ')', '[', ']', ','}
OPERATORS = {'+', '-', '*', '/', '>', '<', '==', '='}
β Purpose: Define sets of punctuation symbols and operators for use in tokenization.
token_specification = [
('KEYWORD', r'\b(?:int|float|char|double|long|short|string|main|function)\b'),
('IDENTIFIER', r'[a-zA-Z_][a-zA-Z0-9_]*'),
('FLOAT_LITERAL', r'\d+\.\d+'),
('INT_LITERAL', r'\d+'),
('STRING_LITERAL', r'"[^"]*"'),
('OPERATOR', r'==|=|\+|-|\*|/|>|<'),
('PUNCTUATOR', r'[;{}\(\)\[\],]'),
('SKIP', r'[ \t]+'),
('MISMATCH', r'.'),
]
β Purpose: Specifies token types and their regex patterns for breaking each line into
meaningful parts:
ββ Keywords, identifiers, literals, operators, punctuators, etc.β
token_regex = '|'.join(f'(?P<{name}>{pattern})' for name, pattern in token_specification)
β Purpose: Dynamically compiles a single regular expression from all token specifications
using named groups.
def tokenize(line):
for match in re.finditer(token_regex, line):
kind = match.lastgroup
value = match.group()
if kind == 'SKIP':
continue
elif kind == 'MISMATCH':
print(f'Unexpected character: {value}')
else:
print(f'{kind}: {value}')
β Purpose: Defines a tokenizer function to parse each line and print categorized tokens.
Skips spaces and flags unmatched characters.
block_stack = []
var_decl_stack = []
main_found = False
β Purpose:
ββ block_stack: Keeps track of open blocks (main/function/other).β
ββ var_decl_stack: Maintains declared variables per block.β
ββ main_found: Flag to check if the main block exists.β
with open('input.txt', 'r') as file:
β Purpose: Opens the input file for reading line by line.
for line_number, line in enumerate(file, 1):
line = line.strip()
β Purpose: Iterates through each line, removes leading/trailing whitespace, and keeps track of
line numbers for error reporting.
if not line or line.startswith('//'):
continue
β Purpose: Skips empty lines and single-line comments.
if re.match(main_pattern, line):
block_stack.append('main')
var_decl_stack.append(set())
main_found = True
continue
β Purpose: Detects and opens the main block, adds to block and variable tracking, and sets
the main_found flag.
elif re.match(function_pattern, line):
block_stack.append('function')
var_decl_stack.append(set())
continue
β Purpose: Detects and opens a function block, adds to stacks.
elif re.match(dictionary_pattern, line):
block_stack.append('dictionary')
var_decl_stack.append(set())
continue
β Purpose: Detects a named block or "dictionary-style" block and tracks it.
elif line == '}':
if block_stack:
block_stack.pop()
var_decl_stack.pop()
else:
print(f'Line {line_number}: Unexpected closing brace')
continue
β Purpose: Handles closing blocks }, popping them from both the block and variable stacks.
Warns on unbalanced closing braces.
if not block_stack:
print(f'Line {line_number}: Code outside of any block is not allowed')
continue
β Purpose: Prevents code from being written outside of any block.
if re.match(decl_pattern, line):
β Purpose: Detects and handles variable declarations.
parts = line.split('=')
var_part = parts[0].strip()
var_name = var_part.split()[1].split('[')[0].strip()
β Purpose: Extracts the variable name, handling optional array declaration.
if var_name in var_decl_stack[-1]:
print(f'Line {line_number}: Variable "{var_name}" already declared in this scope')
elif var_name in all_keywords:
print(f'Line {line_number}: Variable name "{var_name}" cannot be a keyword')
else:
var_decl_stack[-1].add(var_name)
β Purpose: Checks for:
ββ Duplicate variable declarations within the same scope.β
ββ Keyword misuse as variable names.β
elif re.match(assign_pattern, line):
continue
β Purpose: Allows valid assignment statements to pass without error.
else:
print(f'Line {line_number}: Invalid syntax')
β Purpose: Catches all lines that do not match any known pattern and reports them as
invalid.
tokenize(line)
β Purpose: Tokenizes every valid line for syntax highlighting/debugging purposes.
if not main_found:
print('Error: main block not found')
if block_stack:
print('Error: Unclosed blocks exist')
β Purpose: Final validation:
ββ Confirms main() block is present.β
ββ Ensures all opened blocks are closed properly.β
Here are the syntax rules of the custom language in plain text format:
1. Variable Declarations
ββ Must begin with a type keyword (int, float, char, double, long, short, string)β
ββ Followed by a valid identifierβ
ββ Optional array notation using square bracketsβ
ββ Optional assignment using =β
ββ Must end with a semicolon ;β
Examples:
ββ int x;β
ββ float y = 3.14;β
ββ string name = "Hazique";β
ββ int arr[10];β
ββ char c = 'a';β
2. Assignment Statements
ββ An identifier followed by = and a value or expressionβ
ββ Must end with a semicolon ;β
Examples:
ββ x = 10;β
ββ name = "John";β
3. Compound and Unary Assignments
ββ Supported operations include: ++, --, +=, -=β
ββ Can appear as prefix or postfix on identifiersβ
ββ May optionally include assignmentβ
Examples:
ββ x++;β
ββ --y;β
ββ z += 5;β
ββ ++counter = 100; (though uncommon, it’s supported by the pattern)β
4. Function Definition
ββ Begins with keyword functionβ
ββ Followed by a valid function name and empty parentheses ()β
ββ Must be followed by a block { ... }β
Example:
ββ function myFunc() {β
5. Main Function
ββ Must be defined once using main()β
ββ Must be followed by a block { ... }β
ββ Serves as the entry point of the programβ
Example:
ββ main() {β
6. Class Declaration
ββ Optional access modifier (public, private, or protected)β
ββ Must be followed by keyword class and a unique class nameβ
ββ Followed by a block { ... }β
Examples:
ββ class MyClass {β
ββ public class Car {β
7. Control Flow Statements
ββ If statement: starts with if, followed by condition in parentheses, and a blockβ
ββ Else statement: starts with else, followed by a blockβ
ββ For loop: for(init; condition; update) followed by a blockβ
Examples:
ββ if (x > 0) {β
ββ else {β
ββ for (int i = 0; i < 10; i++) {β
8. Dictionary-Like Block
ββ Identifier followed directly by an opening brace {β
Example:
ββ data {β
9. Empty Statement
ββ A single semicolon on a line is validβ
Example:
ββ ;β
10. Comments
ββ Lines starting with // are treated as comments and ignoredβ
Example:
ββ // This is a commentβ
11. Syntax Rules and Restrictions
ββ Every opening { must have a matching closing }β
ββ All executable code must be inside a blockβ
ββ Variables cannot be declared multiple times in the same blockβ
ββ Variable names must not be reserved keywordsβ
ββ Only one main() is allowedβ
ββ Classes must not be redeclaredβ
C1 Language CFG
<program>
::= <function_definition> | <program> <function_definition>
<function_definition> ::= <type> <identifier> "(" <parameter_list_opt> ")" "{"
<parameter_list_opt> ::= <parameter_list> | ε
<parameter_list>
::= <parameter> | <parameter> "," <parameter_list>
<parameter>
::= <type> <identifier>
<type>
::= "int"
| "float"
| "char"
| "double"
| "long"
| "short"
| "string"
<identifier>
::= <letter> <identifier_tail>
<identifier_tail>
::= <letter_or_digit> <identifier_tail> | ε
<letter>
<letter_or_digit>
::= [a-zA-Z_]
::= [a-zA-Z0-9_]
Explanation:
ββ <program> is a sequence of one or more function definitions.β
ββ A <function_definition> starts with a <type>, followed by an <identifier>
(function name), a parameter list in parentheses, and an opening curly brace {.β
ββ Parameters inside the parentheses can be empty (ε) or a comma-separated list of typed
identifiers.β
ββ <identifier> follows typical naming rules (letters or underscore followed by
letters/digits/underscore).β
ββ <type> includes the allowed data types only.β
Let me know if you want me to add variable declarations or statements inside function bodies as
well!