The exceptions were interesting. A common approach was a byte code interpreter/machine. This had the advantage of being easier to port, as you only had to port that piece rather than the whole app. Hardware used to be a lot more interesting back then with all sorts of variations on memory addressing modes, size of units of information (bits & bytes), overlaying (you couldn't fit all your code and data in memory at once), file access, and even something as simple as drawing text or graphics on the screen.
An example for games is https://en.wikipedia.org/wiki/SCUMM
UCSD Pascal, and later large parts of Microsoft Excel (plus Word I believe) also used the approach, especially in the latter case because it needed less space - https://en.wikipedia.org/wiki/P-code_machine
Programming back then was very different to today. Virtually everything was constrained by cpu, memory and storage. Writing products involved working out how you could do things despite those, and debugging was not fun. Just like using 9 inch monitors, it seemed fine at the time, but now I really like having almost unbounded everything, and several freaking huge monitors!