nx_step_parse.nx source
↩ module page · 453 lines · 15035 B
1// nx_step_parse.nx -- R1a STEP (ISO-10303-21) STRUCTURE parser LIB (no main; gated by nx_step_parse_gate).
2// The explodeview-parity keystone: STEP is explodeview.com's ENTIRE input format and a named CAD gap since
3// 07-01 (nx_step_import.nx never existed). SCOPE v0 = Part-21 lexing + entity table + the PRODUCT STRUCTURE
4// spine: PRODUCT / PRODUCT_DEFINITION_FORMATION / PRODUCT_DEFINITION / NEXT_ASSEMBLY_USAGE_OCCURRENCE ->
5// assembly tree + BOM. Geometry tessellation (analytic faces then NURBS) = R1b, its own rung.
6// Lexer rules honored: quoted strings (double-quote-escape by doubling), /* */ comments, complex instances
7// ( NAME(..)NAME(..) ), balanced-paren argument spans. The hash character (35) is matched NUMERICALLY --
8// never appears in an nx string literal (compiler gotcha). ctx st: *i64 slots: 0=buf 1=n 2=id[] 3=nameoff[]
9// 4=namelen[] 5=argoff[] 6=arglen[] 7=count 8=cap. license_tier: ORIGINAL
10import "nx_syscalls.nx"
11
12func sp_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
13func sp_putn(v: i64) -> i64 {
14 let bb: *u8 = sys_mmap(28)
15 var m: i64 = v
16 if m < 0 { sp_puts("-" as *u8); m = 0 - m }
17 let t: *u8 = sys_mmap(28)
18 var k: i64 = 0
19 if m == 0 { t[0] = 48 as u8; k = 1 }
20 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
21 var i: i64 = 0
22 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
23 sys_write(1, bb, k)
24 return 0
25}
26
27func sp_read_file(path: *u8, buf: *u8, cap: i64) -> i64 {
28 let fd: i64 = sys_openat_rd(path)
29 if fd < 0 { return 0 - 1 }
30 var off: i64 = 0
31 var going: i64 = 1
32 while going == 1 {
33 if off >= cap { going = 0 } else {
34 let p: *u8 = ((buf as i64) + off) as *u8
35 let r: i64 = sys_read(fd, p, cap - off)
36 if r <= 0 { going = 0 } else { off = off + r }
37 }
38 }
39 sys_close(fd)
40 return off
41}
42
43func sp_init(st: *i64, buf: *u8, n: i64, aid: *i64, anm: *i64, anl: *i64, aao: *i64, aal: *i64) -> i64 {
44 st[0] = buf as i64
45 st[1] = n
46 st[2] = aid as i64
47 st[3] = anm as i64
48 st[4] = anl as i64
49 st[5] = aao as i64
50 st[6] = aal as i64
51 st[7] = 0
52 st[8] = 65536
53 st[9] = sys_mmap(16) as i64
54 return 0
55}
56
57// i at opening quote (39); returns index after the closing quote (STEP escapes a quote by doubling it)
58func sp_skip_string(buf: *u8, n: i64, i: i64) -> i64 {
59 var v: i64 = i + 1
60 var going: i64 = 1
61 while going == 1 {
62 if v >= n { going = 0 } else {
63 if buf[v] == (39 as u8) {
64 if v + 1 < n {
65 if buf[v + 1] == (39 as u8) { v = v + 2 } else { going = 0; v = v + 1 }
66 } else { going = 0; v = v + 1 }
67 } else { v = v + 1 }
68 }
69 }
70 return v
71}
72
73// i at '/'; skip a slash-star comment if present, else advance one
74func sp_skip_comment(buf: *u8, n: i64, i: i64) -> i64 {
75 if i + 1 >= n { return i + 1 }
76 if buf[i + 1] != (42 as u8) { return i + 1 }
77 var v: i64 = i + 2
78 var going: i64 = 1
79 while going == 1 {
80 if v + 1 >= n { going = 0; v = n } else {
81 if buf[v] == (42 as u8) {
82 if buf[v + 1] == (47 as u8) { going = 0; v = v + 2 } else { v = v + 1 }
83 } else { v = v + 1 }
84 }
85 }
86 return v
87}
88
89func sp_isspace(c: i64) -> i64 {
90 if c == 32 { return 1 }
91 if c == 9 { return 1 }
92 if c == 10 { return 1 }
93 if c == 13 { return 1 }
94 return 0
95}
96
97func sp_isnamec(c: i64) -> i64 {
98 if c >= 65 { if c <= 90 { return 1 } }
99 if c >= 48 { if c <= 57 { return 1 } }
100 if c == 95 { return 1 }
101 return 0
102}
103
104// balanced-paren args: v just after the opening paren; out2[0]=argoff out2[1]=arglen; returns index after ')'
105func sp_args_span(buf: *u8, n: i64, v0: i64, out2: *i64) -> i64 {
106 var v: i64 = v0
107 var depth: i64 = 1
108 out2[0] = v
109 out2[1] = 0
110 var going: i64 = 1
111 while going == 1 {
112 if v >= n { going = 0; out2[1] = v - out2[0] } else {
113 let c: u8 = buf[v]
114 if c == (39 as u8) { v = sp_skip_string(buf, n, v) } else {
115 if c == (40 as u8) { depth = depth + 1; v = v + 1 } else {
116 if c == (41 as u8) {
117 depth = depth - 1
118 if depth == 0 { out2[1] = v - out2[0]; going = 0 }
119 v = v + 1
120 } else { v = v + 1 }
121 }
122 }
123 }
124 }
125 return v
126}
127
128// statement starting at the hash char (35) at index i; parse + store; returns resume index
129func sp_statement(st: *i64, i: i64) -> i64 {
130 let buf: *u8 = st[0] as *u8
131 let n: i64 = st[1]
132 var v: i64 = i + 1
133 var id: i64 = 0
134 var got: i64 = 0
135 var going: i64 = 1
136 while going == 1 {
137 if v >= n { going = 0 } else {
138 let c: i64 = buf[v] as i64
139 if c >= 48 { if c <= 57 { id = id * 10 + (c - 48); got = 1; v = v + 1 } else { going = 0 } } else { going = 0 }
140 }
141 }
142 if got == 0 { return v }
143 var sk: i64 = 1
144 while sk == 1 {
145 if v < n { let s1: i64 = sp_isspace(buf[v] as i64); if s1 == 1 { v = v + 1 } else { sk = 0 } } else { sk = 0 }
146 }
147 if v >= n { return v }
148 if buf[v] != (61 as u8) { return v }
149 v = v + 1
150 sk = 1
151 while sk == 1 {
152 if v < n { let s2: i64 = sp_isspace(buf[v] as i64); if s2 == 1 { v = v + 1 } else { sk = 0 } } else { sk = 0 }
153 }
154 if v >= n { return v }
155 var nmoff: i64 = v
156 var nmlen: i64 = 0
157 if buf[v] != (40 as u8) {
158 var nm: i64 = 1
159 while nm == 1 {
160 if v < n { let s3: i64 = sp_isnamec(buf[v] as i64); if s3 == 1 { v = v + 1 } else { nm = 0 } } else { nm = 0 }
161 }
162 nmlen = v - nmoff
163 sk = 1
164 while sk == 1 {
165 if v < n { let s4: i64 = sp_isspace(buf[v] as i64); if s4 == 1 { v = v + 1 } else { sk = 0 } } else { sk = 0 }
166 }
167 }
168 if v >= n { return v }
169 if buf[v] != (40 as u8) { return v }
170 let out2: *i64 = st[9] as *i64
171 let after: i64 = sp_args_span(buf, n, v + 1, out2)
172 v = after
173 var fin: i64 = 1
174 while fin == 1 {
175 if v < n { if buf[v] == (59 as u8) { fin = 0; v = v + 1 } else { v = v + 1 } } else { fin = 0 }
176 }
177 let cnt: i64 = st[7]
178 if cnt >= st[8] { return v }
179 let aid: *i64 = st[2] as *i64
180 let anm: *i64 = st[3] as *i64
181 let anl: *i64 = st[4] as *i64
182 let aao: *i64 = st[5] as *i64
183 let aal: *i64 = st[6] as *i64
184 aid[cnt] = id
185 anm[cnt] = nmoff
186 anl[cnt] = nmlen
187 let ao: i64 = out2[0]
188 let al: i64 = out2[1]
189 aao[cnt] = ao
190 aal[cnt] = al
191 st[7] = cnt + 1
192 return v
193}
194
195// full scan: fills the entity table; returns entity count
196func sp_scan(st: *i64) -> i64 {
197 let buf: *u8 = st[0] as *u8
198 let n: i64 = st[1]
199 var i: i64 = 0
200 while i < n {
201 let c: u8 = buf[i]
202 if c == (39 as u8) { i = sp_skip_string(buf, n, i) } else {
203 if c == (47 as u8) { i = sp_skip_comment(buf, n, i) } else {
204 if c == (35 as u8) { i = sp_statement(st, i) } else { i = i + 1 }
205 }
206 }
207 }
208 return st[7]
209}
210
211func sp_find(st: *i64, id: i64) -> i64 {
212 let aid: *i64 = st[2] as *i64
213 var k: i64 = 0
214 while k < st[7] {
215 if aid[k] == id { return k }
216 k = k + 1
217 }
218 return 0 - 1
219}
220
221func sp_name_is(st: *i64, idx: i64, s: *u8) -> i64 {
222 let buf: *u8 = st[0] as *u8
223 let anm: *i64 = st[3] as *i64
224 let anl: *i64 = st[4] as *i64
225 var sl: i64 = 0
226 while s[sl] != (0 as u8) { sl = sl + 1 }
227 if anl[idx] != sl { return 0 }
228 let off: i64 = anm[idx]
229 var j: i64 = 0
230 while j < sl {
231 if buf[off + j] != s[j] { return 0 }
232 j = j + 1
233 }
234 return 1
235}
236
237func sp_name_prefix(st: *i64, idx: i64, s: *u8) -> i64 {
238 let buf: *u8 = st[0] as *u8
239 let anm: *i64 = st[3] as *i64
240 let anl: *i64 = st[4] as *i64
241 var sl: i64 = 0
242 while s[sl] != (0 as u8) { sl = sl + 1 }
243 if anl[idx] < sl { return 0 }
244 let off: i64 = anm[idx]
245 var j: i64 = 0
246 while j < sl {
247 if buf[off + j] != s[j] { return 0 }
248 j = j + 1
249 }
250 return 1
251}
252
253func sp_name_out(st: *i64, idx: i64) -> i64 {
254 let anm: *i64 = st[3] as *i64
255 let anl: *i64 = st[4] as *i64
256 let p: *u8 = (st[0] + anm[idx]) as *u8
257 sys_write(1, p, anl[idx])
258 return 0
259}
260
261// first entity reference (hash-number) anywhere in the args of entity idx; -1 if none
262func sp_first_ref(st: *i64, idx: i64) -> i64 {
263 let buf: *u8 = st[0] as *u8
264 let aao: *i64 = st[5] as *i64
265 let aal: *i64 = st[6] as *i64
266 var v: i64 = aao[idx]
267 let e: i64 = v + aal[idx]
268 while v < e {
269 let c: u8 = buf[v]
270 if c == (39 as u8) { v = sp_skip_string(buf, e, v) } else {
271 if c == (35 as u8) {
272 var id: i64 = 0
273 var got: i64 = 0
274 var w: i64 = v + 1
275 var going: i64 = 1
276 while going == 1 {
277 if w >= e { going = 0 } else {
278 let d: i64 = buf[w] as i64
279 if d >= 48 { if d <= 57 { id = id * 10 + (d - 48); got = 1; w = w + 1 } else { going = 0 } } else { going = 0 }
280 }
281 }
282 if got == 1 { return id }
283 v = w
284 } else { v = v + 1 }
285 }
286 }
287 return 0 - 1
288}
289
290// k-th (0-based) TOP-LEVEL comma-separated argument span of entity idx; out2[0]=off out2[1]=len; 1 if found
291func sp_arg_span(st: *i64, idx: i64, k: i64, out2: *i64) -> i64 {
292 let buf: *u8 = st[0] as *u8
293 let aao: *i64 = st[5] as *i64
294 let aal: *i64 = st[6] as *i64
295 var v: i64 = aao[idx]
296 let e: i64 = v + aal[idx]
297 var depth: i64 = 0
298 var argi: i64 = 0
299 var start: i64 = v
300 while v <= e {
301 var isend: i64 = 0
302 var c: u8 = 0 as u8
303 if v == e { isend = 1 } else { c = buf[v] }
304 if isend == 0 {
305 if c == (39 as u8) { v = sp_skip_string(buf, e, v) } else {
306 if c == (40 as u8) { depth = depth + 1; v = v + 1 } else {
307 if c == (41 as u8) { depth = depth - 1; v = v + 1 } else {
308 if c == (44 as u8) {
309 if depth == 0 { isend = 1 } else { v = v + 1 }
310 } else { v = v + 1 }
311 }
312 }
313 }
314 }
315 if isend == 1 {
316 if argi == k {
317 out2[0] = start
318 out2[1] = v - start
319 return 1
320 }
321 argi = argi + 1
322 start = v + 1
323 v = v + 1
324 }
325 }
326 return 0
327}
328
329// parse a hash-ref inside an argument span; -1 if the span is not a ref
330func sp_span_ref(buf: *u8, off: i64, len: i64) -> i64 {
331 var v: i64 = off
332 let e: i64 = off + len
333 var sk: i64 = 1
334 while sk == 1 {
335 if v < e { let s: i64 = sp_isspace(buf[v] as i64); if s == 1 { v = v + 1 } else { sk = 0 } } else { sk = 0 }
336 }
337 if v >= e { return 0 - 1 }
338 if buf[v] != (35 as u8) { return 0 - 1 }
339 var id: i64 = 0
340 var got: i64 = 0
341 var w: i64 = v + 1
342 var going: i64 = 1
343 while going == 1 {
344 if w >= e { going = 0 } else {
345 let d: i64 = buf[w] as i64
346 if d >= 48 { if d <= 57 { id = id * 10 + (d - 48); got = 1; w = w + 1 } else { going = 0 } } else { going = 0 }
347 }
348 }
349 if got == 0 { return 0 - 1 }
350 return id
351}
352
353// print the inner text of a quoted-string argument span
354func sp_span_str_out(buf: *u8, off: i64, len: i64) -> i64 {
355 var v: i64 = off
356 let e: i64 = off + len
357 var sk: i64 = 1
358 while sk == 1 {
359 if v < e { let s: i64 = sp_isspace(buf[v] as i64); if s == 1 { v = v + 1 } else { sk = 0 } } else { sk = 0 }
360 }
361 if v >= e { return 0 }
362 if buf[v] != (39 as u8) { return 0 }
363 let s0: i64 = v + 1
364 var w: i64 = s0
365 var going: i64 = 1
366 while going == 1 {
367 if w < e { if buf[w] == (39 as u8) { going = 0 } else { w = w + 1 } } else { going = 0 }
368 }
369 let p: *u8 = ((buf as i64) + s0) as *u8
370 sys_write(1, p, w - s0)
371 return 0
372}
373
374// 1 if entity idx is a PRODUCT whose first argument string equals s
375func sp_prod_name_is(st: *i64, idx: i64, s: *u8) -> i64 {
376 let isp: i64 = sp_name_is(st, idx, "PRODUCT" as *u8)
377 if isp == 0 { return 0 }
378 let buf: *u8 = st[0] as *u8
379 let out2: *i64 = st[9] as *i64
380 let okk: i64 = sp_arg_span(st, idx, 0, out2)
381 if okk == 0 { return 0 }
382 var v: i64 = out2[0]
383 let e: i64 = out2[0] + out2[1]
384 var sk: i64 = 1
385 while sk == 1 {
386 if v < e { let sc: i64 = sp_isspace(buf[v] as i64); if sc == 1 { v = v + 1 } else { sk = 0 } } else { sk = 0 }
387 }
388 if v >= e { return 0 }
389 if buf[v] != (39 as u8) { return 0 }
390 v = v + 1
391 var sl: i64 = 0
392 while s[sl] != (0 as u8) { sl = sl + 1 }
393 var j: i64 = 0
394 while j < sl {
395 if v + j >= e { return 0 }
396 if buf[v + j] != s[j] { return 0 }
397 j = j + 1
398 }
399 if v + sl >= e { return 0 }
400 if buf[v + sl] != (39 as u8) { return 0 }
401 return 1
402}
403
404// resolve a PRODUCT_DEFINITION entity id -> PRODUCT entity idx (PD -> first ref = PDF -> first ref = PRODUCT); -1 on any break
405func sp_pd_product(st: *i64, pdid: i64) -> i64 {
406 let pdi: i64 = sp_find(st, pdid)
407 if pdi < 0 { return 0 - 1 }
408 let ispd: i64 = sp_name_is(st, pdi, "PRODUCT_DEFINITION" as *u8)
409 if ispd == 0 { return 0 - 1 }
410 let pdfid: i64 = sp_first_ref(st, pdi)
411 if pdfid < 0 { return 0 - 1 }
412 let pdfi: i64 = sp_find(st, pdfid)
413 if pdfi < 0 { return 0 - 1 }
414 let ispdf: i64 = sp_name_prefix(st, pdfi, "PRODUCT_DEFINITION_FORMATION" as *u8)
415 if ispdf == 0 { return 0 - 1 }
416 let prid: i64 = sp_first_ref(st, pdfi)
417 if prid < 0 { return 0 - 1 }
418 let pri: i64 = sp_find(st, prid)
419 if pri < 0 { return 0 - 1 }
420 let ispr: i64 = sp_name_is(st, pri, "PRODUCT" as *u8)
421 if ispr == 0 { return 0 - 1 }
422 return pri
423}
424
425// collect assembly edges from NEXT_ASSEMBLY_USAGE_OCCURRENCE entities: pe[i]=parent PD id, ce[i]=child PD id
426func sp_nauo_collect(st: *i64, pe: *i64, ce: *i64, cap: i64) -> i64 {
427 var en: i64 = 0
428 let out2: *i64 = st[9] as *i64
429 let buf: *u8 = st[0] as *u8
430 var k: i64 = 0
431 while k < st[7] {
432 let isn: i64 = sp_name_is(st, k, "NEXT_ASSEMBLY_USAGE_OCCURRENCE" as *u8)
433 if isn == 1 {
434 if en < cap {
435 let ok3: i64 = sp_arg_span(st, k, 3, out2)
436 var pref: i64 = 0 - 1
437 if ok3 == 1 { let pr: i64 = sp_span_ref(buf, out2[0], out2[1]); pref = pr }
438 let ok4: i64 = sp_arg_span(st, k, 4, out2)
439 var cref: i64 = 0 - 1
440 if ok4 == 1 { let cr: i64 = sp_span_ref(buf, out2[0], out2[1]); cref = cr }
441 if pref >= 0 {
442 if cref >= 0 {
443 pe[en] = pref
444 ce[en] = cref
445 en = en + 1
446 }
447 }
448 }
449 }
450 k = k + 1
451 }
452 return en
453}