Manufacturing Control is a bill-of-materials and shop-floor cost management system that stores up to 150 records in a 150×49 character string array. Each record packs part number, department, operation, labor cost, material cost, overhead cost, where-used linkage, quantity per assembly, scrap factor, hours per thousand, and part type (Detail or Assembly) into fixed-width substrings of a single row in R$. The program provides a nine-option menu covering record add, delete, file listing, total cost computation, per-part cost computation, bill-of-materials explosion (finding all components of a parent), and implosion (finding all parents of a component). Numeric fields are stored and retrieved as strings using STR$ and VAL, and the scrap factor is applied during cost rollups with the formula QX=(SC*(Q*NP))+(Q*NP).
Program Analysis
Program Structure
The program is organized as a dispatch loop: lines 20–180 initialize global variables, display a splash screen, and then repeatedly call the menu subroutine at line 1000, branching to one of nine functional subroutines based on the value of C. The main loop at line 999 (GOTO 90) re-enters the menu after each operation. Line 180 handles option 9 as a STOP.
| Line Range | Function |
|---|---|
| 20–180 | Initialization, splash screen, dispatch loop |
| 1000–1122 | Menu display and input |
| 1500–1999 | Add record (calls 1520, 2000, 3000) |
| 2000–2040 | Pad P$, D$, O$ to fixed widths |
| 2500–2999 | Delete record (blank first byte) |
| 3000–3499 | Write record into R$ array |
| 3500–3999 | List file (all non-blank records) |
| 4000–4010 | Assembly stub: zero M, fall into cost input at 1610 |
| 4500–4799 | Compute total costs across all records |
| 5500–5999 | Compute costs for a specific part number |
| 6000–6020 | Pause/continue subroutine (also supports ‘Q’ to return to menu) |
| 6500–6699 | BOM explosion (find components of a parent) |
| 7500–7799 | BOM implosion (find parents of a component) |
| 8500–8600 | Save data to tape, restart |
Data Storage Layout
All data is held in R$(150,49), a two-dimensional string array of 150 rows, each 49 characters wide. Fields are packed into fixed-width subcolumns using substring slicing. Numeric values are stored as strings via STR$ and decoded with VAL on retrieval. A record is considered deleted when its first byte is set to a space (R$(N,1 TO 1)=" ").
| Columns | Width | Field |
|---|---|---|
| 1–5 | 5 | Part number (P$) |
| 6–9 | 4 | Department (D$) |
| 10–13 | 4 | Operation (O$) |
| 14–19 | 6 | Labor cost/hour (L) |
| 20–25 | 6 | Material cost/1000 (M) |
| 26–31 | 6 | Overhead cost/hour (H) |
| 32–36 | 5 | Where-used parent part (W$) |
| 37–38 | 2 | Quantity per assembly (NP) |
| 39–43 | 5 | Scrap factor (SC) |
| 44–48 | 5 | Hours per 1000 (HP) |
| 49 | 1 | Type: D=Detail, A=Assembly (E$) |
Key BASIC Idioms
- Fixed-width string padding is applied in subroutine 2000: short inputs are extended with trailing spaces using concatenation, e.g.
LET P$=P$+" ", ensuring substring slicing always works correctly. - The line
3040 LET R$(N,14 TO 19)=STR$ Lillustrates the pattern of embedding numeric values in string records; all cost and quantity fields are stored this way. - Inverse-video text (e.g.
"%M%E%N%U%") is used for headings, labels, and status messages throughout, giving a highlighted appearance on screen. - The
SLOW/FASTmode switches are placed around computation-heavy loops to maximize performance during file scans and revert to display-quality mode for output. - The pause subroutine at line 6000 doubles as a menu-exit shortcut: entering “Q” triggers
GOTO 90, returning to the main dispatch loop without unwinding the call stack normally.
Cost Computation
The scrap-adjusted quantity formula used in both total-cost (line 4528) and part-cost (line 5607) routines is:
QX = (SC * (Q * NP)) + (Q * NP)
This computes the gross quantity needed including scrap loss. Labor and overhead costs are then multiplied by hours per 1000 (HP) since the rates are expressed per hour. All costs are normalized to a base of 1000 parts, and the part-cost routine accepts an arbitrary quantity Q which is divided by 1000 at line 5555 before use.
BOM Explosion and Implosion
Explosion (option 6, subroutine 6500) searches all records where the where-used field (R$(N,32 TO 36)) matches the entered parent part number, listing all immediate children. Implosion (option 7, subroutine 7500) does the reverse: it searches for records whose part number field (R$(N,1 TO 5)) matches the entered part, and displays which parent assembly it belongs to from its where-used field. Neither routine performs recursive multi-level traversal; they are single-level lookups only.
Notable Techniques and Anomalies
- The
LCcounter (line counter) at lines 3522–3524, 6590–6592, and 7620–7622 tracks printed records and calls the pause subroutine after every 3 records to prevent screen scroll overflow. However,LCis not reset inside the listing loops themselves — it is only reset in the pause subroutine at line 6015. This means if the user does not press “Q” mid-listing, paging works correctly, but if the subroutine is called at the end of a listing withLCnot equal to 3, the extraGOSUB 6000at the end of each listing routine still provides a final pause. - The Assembly add path (option 1 with E$=”A”) skips the material cost input at line 1635 (
IF E$="A" THEN GOTO 1670), leavingM=0as set at line 4004. This is intentional: assemblies typically have no direct material cost. - The delete routine at line 2550 only blanks the first byte of a record (
R$(N,1 TO 1)=" "), leaving the rest of the data in memory. This is a deliberate soft-delete: the file search routines treat any record with a blank first byte as an empty slot. - Line 1120 branches to 1090 on invalid menu input — an efficient re-prompt that redisplays from the “8=SAVE DATA” line rather than the full menu, saving screen redraws.
- The
SAVE S$at line 8580 saves the entire program including the populatedR$array, providing a simple but effective data persistence mechanism without any separate data file handling. - The
STR$conversion at lines 3040–3090 does not guarantee fixed-width output — a short numeric result fromSTR$will be left-aligned in its field with no padding. This can cause misalignment whenVALreads back a substring that contains part of an adjacent field’s data, though in practice the fixed-column slicing keeps fields isolated as long as numbers don’t exceed their allotted widths.
Content
Source Code
20 DIM R$(150,49)
22 LET XJ=150
25 LET TL=0
27 LET TM=0
28 LET TH=0
30 LET LC=0
40 SLOW
50 PRINT AT 10,10;"TS1000"
60 PRINT AT 11,7;"MANUFACTURING"
70 PRINT AT 12,7;"CONTROL SYSTEM"
80 GOSUB 6000
90 GOSUB 1000
100 IF C=1 THEN GOSUB 1500
110 IF C=2 THEN GOSUB 2500
120 IF C=3 THEN GOSUB 3500
130 IF C=4 THEN GOSUB 4500
140 IF C=5 THEN GOSUB 5500
150 IF C=6 THEN GOSUB 6500
160 IF C=7 THEN GOSUB 7500
170 IF C=8 THEN GOSUB 8500
180 IF C=9 THEN STOP
999 GOTO 90
1000 REM MENU
1010 CLS
1020 PRINT AT 2,0;"%M%E%N%U% %S%E%L%E%C%T%I%O%N% %P%A%N%E%L"
1030 PRINT AT 4,4;"1=ADD PART/DEPT/OPER"
1040 PRINT AT 6,4;"2=DELETE PART/DEPT/OPER"
1050 PRINT AT 8,4;"3=LIST FILE"
1060 PRINT AT 10,4;"4=COMPUTE TOTAL COSTS"
1070 PRINT AT 12,4;"5=COMPUTE PART COST"
1080 PRINT AT 14,4;"6=EXPLODE PART"
1085 PRINT AT 16,4;"7=IMPLODE PART"
1090 PRINT AT 18,4;"8=SAVE DATA"
1095 PRINT AT 20,4;"9=QUIT"
1100 PRINT "%E%N%T%E%R% %O%P%T%I%O%N% %C%O%D%E"
1110 INPUT C
1115 PRINT AT 21,20;C
1120 IF C<1 OR C>9 THEN GOTO 1090
1122 RETURN
1500 REM ADD
1510 CLS
1515 GOSUB 1520
1517 GOTO 1744
1520 PRINT "ENTER PART NO. 5 DIGITS"
1530 INPUT P$
1540 PRINT P$
1550 PRINT "ENTER DEPT 4 DIGITS"
1560 INPUT D$
1570 PRINT D$
1580 PRINT "ENTER OPERATION 4 DIGITS"
1590 INPUT O$
1600 PRINT O$
1602 GOSUB 2000
1605 RETURN
1610 PRINT "I/P LABOR COST/HOUR--6 DIGITS"
1620 INPUT L
1630 PRINT L
1635 IF E$="A" THEN GOTO 1670
1640 PRINT "I/P MATERIAL COST/1000--6 DIGITS"
1650 INPUT M
1660 PRINT M
1670 PRINT "I/P OVERHEAD COST/HOUR--6 DIGITS"
1682 INPUT H
1684 PRINT H
1686 PRINT "I/P SCRAP FACTOR--3 DEC. DIGITS"
1687 INPUT SC
1688 PRINT SC
1690 PRINT "I/P HOURS/1000 - 5 DIGITS"
1692 INPUT HP
1694 PRINT HP
1700 PRINT "ENTER WHERE USED 5 DIGITS"
1710 INPUT W$
1720 PRINT W$
1722 LET W=LEN W$
1725 IF W<5 THEN LET W$=W$+" "
1730 PRINT "ENTER NO. PER ASSY"
1740 INPUT NP
1742 PRINT NP
1743 GOTO 1752
1744 PRINT "ENTER D = DETAIL OR A = ASSY"
1746 INPUT E$
1748 PRINT E$
1749 IF E$="D" THEN GOTO 1610
1750 GOTO 4000
1752 FAST
1753 CLS
1760 FOR N=1 TO XJ
1765 IF P$(1 TO 5)=R$(N,1 TO 5) AND D$(1 TO 4)=R$(N,6 TO 9) AND O$(1 TO 4)=R$(N,10 TO 13) THEN GOTO 1800
1770 NEXT N
1790 PRINT "%R%E%C%O%R%D% %A%D%D%E%D"
1792 GOSUB 3000
1796 GOTO 1998
1800 SLOW
1810 PRINT "%R%E%C%O%R%D ALREADY EXISTS"
1820 PRINT
1830 PRINT "YOU MADE AN ERROR"
1840 PRINT
1842 PRINT "PRESS %E%N%T%E%R"
1850 INPUT Y$
1998 SLOW
1999 RETURN
2000 REM
2002 LET P=LEN P$
2010 IF P<5 THEN LET P$=P$+" "
2012 LET D=LEN D$
2020 IF D<4 THEN LET D$=D$+" "
2025 LET O=LEN O$
2030 IF O<4 THEN LET O$=O$+" "
2040 RETURN
2500 REM DEL
2505 CLS
2510 GOSUB 1520
2515 FAST
2520 FOR N=1 TO XJ
2530 IF P$(1 TO 5)=R$(N,1 TO 5) AND D$(1 TO 4)=R$(N,6 TO 9) AND O$(1 TO 4)=R$(N,10 TO 13) THEN GOTO 2550
2540 NEXT N
2550 CLS
2555 LET R$(N,1 TO 1)=" "
2560 PRINT "RECORD DELETED"
2565 SLOW
2570 GOSUB 6000
2580 GOTO 2999
2999 RETURN
3000 REM
3002 FOR N=1 TO XJ
3004 IF R$(N,1 TO 1)=" " THEN GOTO 3010
3006 NEXT N
3008 PRINT "SORRY-FILE FULL"
3009 GOTO 3100
3010 LET R$(N,1 TO 5)=P$
3020 LET R$(N,6 TO 9)=D$
3030 LET R$(N,10 TO 13)=O$
3040 LET R$(N,14 TO 19)=STR$ L
3050 LET R$(N,20 TO 25)=STR$ M
3052 LET R$(N,26 TO 31)=STR$ H
3060 LET R$(N,32 TO 36)=W$
3070 LET R$(N,37 TO 38)=STR$ NP
3080 LET R$(N,39 TO 43)=STR$ SC
3090 LET R$(N,44 TO 48)=STR$ HP
3092 LET R$(N,49 TO 49)=E$
3100 GOSUB 6000
3499 RETURN
3500 REM CHANGE
3504 FAST
3505 CLS
3506 FOR N=1 TO XJ
3508 IF R$(N,1 TO 1)=" " THEN GOTO 3600
3509 PRINT "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
3510 PRINT "%P%A%R%T ";R$(N,1 TO 5);" %D%E%P%T ";R$(N,6 TO 9)
3512 PRINT "%O%P%E%R ";R$(N,10 TO 13);" %L%A%B%O%R ";R$(N,14 TO 19)
3514 PRINT "%M%A%T%L ";R$(N,20 TO 25);" %O%V%H%D ";R$(N,26 TO 31)
3515 PRINT "%U%S%E%D ";R$(N,32 TO 36);" %Q%T%Y%/%P%E%R ";R$(N,37 TO 38)
3517 PRINT "%S%C%R%A%P ";R$(N,39 TO 43);" %H%O%U%R%S ";R$(N,44 TO 48)
3519 PRINT "%T%Y%P%E ";R$(N,49 TO 49)
3522 LET LC=LC+1
3524 IF LC=3 THEN GOSUB 6000
3600 NEXT N
3610 SLOW
3700 GOSUB 6000
3999 RETURN
4000 REM
4004 LET M=0
4010 GOTO 1610
4500 REM
4501 LET TT=0
4502 LET TL=0
4503 LET TM=0
4504 LET TH=0
4505 FAST
4507 LET Q=1
4510 FOR N=1 TO XJ
4520 IF R$(N,1 TO 1)=" " THEN GOTO 4700
4525 LET SC=VAL R$(N,39 TO 43)
4527 LET NP=VAL R$(N,37 TO 38)
4528 LET QX=(SC*(Q*NP)+(Q*NP))
4530 LET TL=TL+(QX*(VAL R$(N,14 TO 19)*VAL R$(N,44 TO 48)))
4540 LET TM=TM+(QX*VAL R$(N,20 TO 25))
4550 LET TH=TH+(QX*(VAL R$(N,26 TO 31)*VAL R$(N,44 TO 48)))
4560 LET TT=TT+(QX*VAL R$(N,44 TO 48))
4700 NEXT N
4710 CLS
4712 SLOW
4720 PRINT
4730 PRINT "%T%O%T%A%L% %L%A%B%O%R = ";TL
4740 PRINT "%T%O%T%A%L% %M%A%T%E%R%I%A%L = ";TM
4744 PRINT "%T%O%T%A%L% %O%V%E%R%H%E%A%D = ";TH
4746 PRINT "%T%O%T%A%L% %H%O%U%R%S = ";TT
4748 PRINT
4749 PRINT "ALL ABOVE BASED ON 1000 PARTS"
4750 GOSUB 6000
4799 RETURN
5500 REM
5502 LET TL=0
5504 LET TM=0
5505 LET TT=0
5506 LET TH=0
5510 CLS
5520 PRINT "ENTER QTY TO BE MADE"
5530 INPUT Q
5540 PRINT Q
5550 PRINT
5555 LET Q=Q/1000
5560 PRINT "ENTER PART NO."
5570 INPUT P$
5580 PRINT P$
5581 FAST
5582 GOSUB 2000
5585 FOR N=1 TO XJ
5600 IF P$(1 TO 5)<>R$(N,1 TO 5) AND P$(1 TO 5)<>R$(N,32 TO 36) THEN GOTO 5700
5605 LET SC=VAL R$(N,39 TO 43)
5606 LET NP=VAL R$(N,37 TO 38)
5607 LET QX=(SC*Q*NP)+Q*NP
5610 LET TL=TL+(QX*(VAL R$(N,14 TO 19)*VAL R$(N,44 TO 48)))
5620 LET TM=TM+(QX*VAL R$(N,20 TO 25))
5630 LET TH=TH+(QX*(VAL R$(N,26 TO 31)*VAL R$(N,44 TO 48)))
5632 LET TT=TT+(QX*VAL R$(N,44 TO 48))
5700 NEXT N
5710 SLOW
5740 PRINT "%T%O%T%A%L% %E%X%T%.% %L%A%B%O%R =";TL
5750 PRINT "%T%O%T%A%L% %E%X%T%.% %M%A%T%L =";TM
5760 PRINT "%T%O%T%A%L% %E%X%T%.% %O%V%H%D =";TH
5762 PRINT "%T%O%T%A%L% %E%X%T%.% %H%O%U%R%S =";TT
5780 GOSUB 6000
5999 RETURN
6000 PRINT AT 21,0;"%P%R%E%S%S% %E%N%T%E%R% OR ENTER A Q"
6010 INPUT Y$
6011 IF Y$="Q" THEN SLOW
6012 IF Y$="Q" THEN GOTO 90
6015 LET LC=0
6017 CLS
6020 RETURN
6500 REM
6510 CLS
6520 PRINT "ENTER PART TO BE EXPLODED"
6530 INPUT W$
6535 PRINT W$
6536 LET W=LEN W$
6538 IF W<5 THEN LET W$=W$+" "
6540 FAST
6550 FOR N=1 TO XJ
6560 IF R$(N,1 TO 1)=" " THEN GOTO 6600
6570 IF W$(1 TO 5)<>R$(N,32 TO 36) THEN GOTO 6600
6575 PRINT "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
6580 PRINT R$(N,32 TO 36);"---";"%P%A%R%T ";R$(N,1 TO 5)
6582 PRINT "%D%E%P%T ";R$(N,6 TO 9)
6584 PRINT "%O%P%E%R ";R$(N,10 TO 13)
6586 PRINT "%Q%T%Y%/%P%E%R ";R$(N,37 TO 38)
6588 PRINT "%T%Y%P%E ";R$(N,49 TO 49)
6590 LET LC=LC+1
6592 IF LC=3 THEN GOSUB 6000
6600 NEXT N
6605 SLOW
6610 GOSUB 6000
6699 RETURN
7500 REM
7510 CLS
7520 PRINT "ENTER PART TO BE IMPLODED"
7530 INPUT P$
7540 PRINT P$
7550 GOSUB 2000
7555 FAST
7560 FOR N=1 TO XJ
7570 IF P$(1 TO 5)<>R$(N,1 TO 5) THEN GOTO 7700
7580 PRINT "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
7590 PRINT R$(N,1 TO 5);"---";" %U%S%E%D ";R$(N,32 TO 36)
7600 PRINT "%D%E%P%T ";R$(N,6 TO 9)
7610 PRINT "%O%P%E%R ";R$(N,10 TO 13)
7612 PRINT "%Q%T%Y%/%P%E%R ";R$(N,37 TO 38)
7614 PRINT "%T%Y%P%E ";R$(N,49 TO 49)
7620 LET LC=LC+1
7622 IF LC=3 THEN GOSUB 6000
7700 NEXT N
7705 SLOW
7710 GOSUB 6000
7799 RETURN
8500 REM
8510 CLS
8520 PRINT "ENTER NAME OF FILE"
8530 INPUT S$
8540 PRINT S$
8550 PRINT "SET RECORDER FOR SAVE MODE"
8560 PRINT "PRESS ENTER WHEN READY"
8570 INPUT Y$
8580 SAVE S$
8590 CLS
8600 GOTO 40
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

