-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlexer.py
More file actions
135 lines (104 loc) · 5.26 KB
/
Copy pathlexer.py
File metadata and controls
135 lines (104 loc) · 5.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
"""
lexer.py – Tokenizer for C-like source code
==============================================
Converts a raw source string into a flat list of (token_type, value) tuples.
Token types produced:
KEYWORD – reserved word: int, float, char, double, void, return, …
IDENTIFIER – variable / function name: myVar, sum, main, printf
NUMBER – integer literal: 0, 42, 100
FLOAT – floating-point literal: 3.14, 0.5
STRING – double-quoted string: "hello"
CHAR_LIT – single-quoted char: 'a'
OPERATOR – operator: = + - * / % == != < > <= >=
SYMBOL – punctuation: ( ) { } [ ] ; , .
PREPROCESSOR– lines that start with #: #include <stdio.h>
UNKNOWN – anything the lexer cannot classify (reported but not fatal)
"""
import re
# ──────────────────────────────────────────────────────────────────────
# KEYWORDS
# ──────────────────────────────────────────────────────────────────────
KEYWORDS = {
'int', 'float', 'char', 'double', 'void',
'if', 'else', 'while', 'for', 'return',
'break', 'continue', 'struct', 'true', 'false',
}
# ──────────────────────────────────────────────────────────────────────
# TOKEN RULES (order matters — most specific first)
# ──────────────────────────────────────────────────────────────────────
TOKEN_RULES = [
# Preprocessor — whole line starting with #
('PREPROCESSOR', r'#[^\n]*'),
# Literals
('FLOAT', r'\d+\.\d+'), # 3.14 must come before NUMBER
('NUMBER', r'\d+'), # 42
('STRING', r'"[^"]*"'), # "hello world"
('CHAR_LIT', r"'[^'\\]'|'\\.'"), # 'a' '\n'
# Multi-character operators first, then single-character
('OPERATOR', r'==|!=|<=|>=|&&|\|\||[+\-*/%=<>!]'),
# Punctuation
('SYMBOL', r'[(){}\[\];,.]'),
# Names
('IDENTIFIER', r'[A-Za-z_]\w*'),
# Noise — skip
('WHITESPACE', r'\s+'),
# Catch-all
('UNKNOWN', r'.'),
]
MASTER_PATTERN = re.compile(
'|'.join(f'(?P<{name}>{pat})' for name, pat in TOKEN_RULES)
)
# ──────────────────────────────────────────────────────────────────────
# PUBLIC API
# ──────────────────────────────────────────────────────────────────────
def tokenize(source_code: str) -> list:
"""
Convert *source_code* into a list of (token_type, value) tuples.
- Whitespace is discarded.
- IDENTIFIER tokens that are reserved words become KEYWORD.
- UNKNOWN tokens are kept so downstream stages can report them.
Parameters
----------
source_code : str Raw C-like source text.
Returns
-------
list of (str, str) e.g. [('KEYWORD','int'), ('IDENTIFIER','x'), …]
"""
tokens = []
for match in MASTER_PATTERN.finditer(source_code):
tok_type = match.lastgroup
value = match.group()
if tok_type == 'WHITESPACE':
continue # whitespace carries no meaning
if tok_type == 'IDENTIFIER' and value in KEYWORDS:
tok_type = 'KEYWORD' # promote reserved words
tokens.append((tok_type, value))
return tokens
# ──────────────────────────────────────────────────────────────────────
# OPTIONAL PRETTY PRINTER
# ──────────────────────────────────────────────────────────────────────
def print_tokens(tokens: list) -> None:
"""Print the token list in a neat aligned table."""
print(f"\n{'TOKEN TYPE':<16} VALUE")
print("─" * 36)
for tok_type, value in tokens:
print(f" {tok_type:<14} {value}")
print()
# ──────────────────────────────────────────────────────────────────────
# SELF-TEST
# ──────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
sample = """
#include <stdio.h>
int main() {
int a = 10;
float b = 3.14;
int sum = a + b;
printf("result = %d", sum);
return 0;
}
"""
print("Source:")
print(sample)
toks = tokenize(sample)
print_tokens(toks)