Version 1.0
Copyright © 2022 Lowell D. Thomas
Python APG
 … an ABNF Parser Generator
udts.py
Go to the documentation of this file.
1 ''' @file examples/exp/udts.py
2 @brief Demonstrates using User-Defined Terminals (UDTs).
3 '''
4 import sys
5 import os
6 # add the current working directory to the path
7 # DO NOT MOVE THE FOLLOWING STATEMENT
8 # if using autopep8 formatter, for example, set argument '--ignore=E402'
9 sys.path.append(os.getcwd())
10 from apg_py.exp.exp import ApgExp
11 from apg_py.lib import identifiers as id
12 
13 title = '''This example will demonstrate how to use
14 handwritten code snippets to match patterns that are
15 difficult to describe with an SABNF grammar.
16 An IPv4 address is simple to describe verbally,
17 but the constraints on the digits are quite complicated
18 in the ABNF syntax. For example, with the form
19 xxx.xxx.xxx.xxx
20 xxx can be any number 0-255. However,
21  - it may or may not have leading zeros
22  - if three digits, the first must be <= 2
23  - if 2, the second digit must be <= 5
24  - if 2 and the second digit is 5 then the third must be <= 5
25 Straight forward verbally but not a simple ABNF problem.
26 Here we show a brute force the solution with a handwritten
27 phrase-matching terminal, an APG UDT.
28 '''
29 print()
30 print(title)
31 
32 pattern = 'ipv4 = %^ u_digits %d46 u_digits %d46 u_digits %d46 u_digits %$\n'
33 print()
34 print('PATTERN - Note the use of anchors. Must match the entire string.')
35 print(pattern)
36 header = 'RESULT'
37 testno = 0
38 
39 
40 def u_digits(cb_data):
41  '''A handwritten code snippet to recognize an IPv4 digit 0 - 255.'''
42  digits = 0
43  count = 0
44  for i in range(cb_data['phrase_index'], cb_data['sub_end']):
45  c = cb_data['input'][i]
46  if(c < 48 or c > 57):
47  # not a decimal digit
48  break
49  digits = 10 * digits + (c - 48)
50  count += 1
51  if(count == 3):
52  break
53  if(count > 0 and digits <= 255):
54  # success
55  cb_data['state'] = id.MATCH
56  cb_data['phrase_length'] = count
57  else:
58  # failure
59  cb_data['state'] = id.NOMATCH
60  cb_data['phrase_length'] = 0
61 
62 
63 # the full result
64 exp = ApgExp(pattern)
65 exp.define_udts({'u_digits': u_digits})
66 exp.include(['u_digits'])
67 input = '192.168.001.1'
68 result = exp.exec(input)
69 testno += 1
70 print('\n' + str(testno) + ') Valid IPv4.')
71 print('input string: ' + input)
72 print(header)
73 print(result)
74 
75 # max
76 input = '255.001.01.000'
77 result = exp.test(input)
78 testno += 1
79 print('\n' + str(testno) + ') Max/min IPv4.')
80 print('input string: ' + input)
81 print(header)
82 print(result)
83 
84 # bad numbers
85 input = '256.001.01.000'
86 result = exp.test(input)
87 testno += 1
88 print('\n' + str(testno) + ') Bad IPv4.')
89 print('input string: ' + input)
90 print(header)
91 print(result)
92 
93 input = '255.255.255.300'
94 result = exp.test(input)
95 testno += 1
96 print('\n' + str(testno) + ') Bad IPv4.')
97 print('input string: ' + input)
98 print(header)
99 print(result)
100 
101 input = '255.255.255'
102 result = exp.test(input)
103 testno += 1
104 print('\n' + str(testno) + ') Bad IPv4.')
105 print('input string: ' + input)
106 print(header)
107 print(result)
The ApgExp class provides a pattern-matching engine similar to JavaScript's RegExp
Definition: exp.py:79
def u_digits(cb_data)
A handwritten code snippet to recognize an IPv4 digit 0 - 255.
Definition: udts.py:40
Python APG, Version 1.0, is licensed under the 2-Clause BSD License,
an Open Source Initiative Approved License.