code wiki / (root) / nx_step_parse.nx

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}