diff --git a/.vscode/settings.json b/.vscode/settings.json index c304733..854fb8f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,6 +10,8 @@ "iostream", "memcpy", "pseudocode", + "stringstream", + "strncpy", "struct", "structs" ], diff --git a/README.md b/README.md index 74bbc01..7457a22 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ the 64 bit ARM Instruction Set Architecture (ISA). | 5 | [Interlude - Load and Store](./section_1/regs/ldr.md) | | 6 | [Calling and Returning From Functions](./section_1/funcs/README.md) | | 7 | [Passing Parameters To Functions](./section_1/funcs/README2.md) | +| 8 | [FizzBuzz - a Complete Program](./section_1/fizzbuzz/README.md) | ## Section 2 - Stuff diff --git a/section_1/fizzbuzz/README.md b/section_1/fizzbuzz/README.md new file mode 100644 index 0000000..ffffbfb --- /dev/null +++ b/section_1/fizzbuzz/README.md @@ -0,0 +1,51 @@ +# Section 1 / Chapter 8 / FizzBuzz + +In this chapter we build the classic tech interview question: FizzBuzz. + +The idea is simple. Write a program that enumerates the integers from 0 to some stopping value, perhaps 100. + +For each integer: + +* If it is a multiple of 3, print Fizz + +* If it is a multiple of 5, print Buzz + +* If it is a multiple of both 3 *and* 5, print FizzBuzz + +* Otherwise, if none of the above applies, print the integer. + +The interviewer's hope is that you get twisted in knots trying +to navigate the case where the integer is a multiple of both 3 and +5. There are many ways to solve this challenge. + +One way might be to test for being a multiple of 15 *first* and print +FizzBuzz if true. Then test against 3 and then against 5. + +Another way is to accumulate the correct out by testing against 3 and +adding Fizz to a buffer. Then test against 5 and if appropriate append +Buzz to the buffer. Either the buffer was empty, in which case you get +Buzz alone - or it already contained Fizz in which case the buffer now +contains FizzBuzz. Finally, if *anything* is in the buffer, cause the +buffer to be printed and append a new line. + +In C++, the buffer could be a C++ string or a stringstream. In C +you might think that you must resort to using an array of `char` to +act as the buffer, filling it with `strncpy` or some such nonsense. + +But you don't have to bother! `printf` is a buffered output stream. +It won't print anything until it encounters a new line character. + +In this program, we'll use this to buffer up either Fizz, Buzz or +both then as indicated above, we'll end with a new line and BAM - +whatever was in the `printf` buffer gets sent to the console. + +[Here is a video](https://youtu.be/aJSGTIxu4ik) where we walk through +the process of writing FizzBuzz from scratch in ARM 64 bit assembly +language. + +[Here is the source code](./fizzbuzz.s). + +The video is long but there is much benefit to be had by watching +and listening to another person's process as they write the code. +**AND especially** listening and watching to them debug when +things go wrong! diff --git a/section_1/fizzbuzz/fizzbuzz.s b/section_1/fizzbuzz/fizzbuzz.s index ca6ee2b..4ca4602 100644 --- a/section_1/fizzbuzz/fizzbuzz.s +++ b/section_1/fizzbuzz/fizzbuzz.s @@ -1,91 +1,93 @@ -/* Perry Kivolowitz - CSC3510 -*/ - .global main - .text - .align 2 + .global main + .text + .align 2 /* FizzBuzz - a classic interview question. - Count from 0 to n (let's make it 100). - If the value is divisible by 3, print Fizz - If the value is divisible by 5, print Buzz - If the value is divisible by both 3 and 5, print FizzBuzz - Otherwise, print the number. + Count from 0 to n (let's make it 100). + If the value is divisible by 3, print Fizz + If the value is divisible by 5, print Buzz + If the value is divisible by both 3 and 5, print FizzBuzz + Otherwise, print the number. */ /* Bible: - x20 counter - w21 bool that says whether or not I have printed anything + x20 counter + w21 bool that says whether or not I have printed anything */ /* mod(a, b) - implements a % b - integer divide a by b - for example - 5 % 3 would need 5 // 3 yielding 1 - multiply result by b - 1 * 3 is 3 - subtract result from a - 5 - 3 yielding 2 and that's our return value. + a comes to us in x0 + b comes to us in x1 + method: + integer divide a by b - for example - 5 % 3 + would need 5 // 3 yielding 1 + multiply result by b - 1 * 3 is 3 + subtract result from a - 5 - 3 yielding 2 + and that's our return value. */ mod: sdiv x2, x0, x1 // x2 gets a // b - msub x0, x2, x1, x0 // x0 gets a - a // b * b - ret + msub x0, x2, x1, x0 // x0 gets a - a // b * b + ret main: stp x20, x30, [sp, -16]! - str x21, [sp, -16]! + str x21, [sp, -16]! - mov x20, xzr + mov x20, xzr 1: cmp x20, 100 - bge 99f + bge 99f - mov w21, wzr + mov w21, wzr - // Test for divisible by 3 - mov x0, x20 - mov x1, 3 - bl mod - cbnz x0, 5f - // If we get here, the counter was divisible by 3 - ldr x0, =fizz - bl printf - add w21, w21, 1 + // Test for divisible by 3 + mov x0, x20 + mov x1, 3 + bl mod + cbnz x0, 5f + // If we get here, the counter was divisible by 3 + ldr x0, =fizz + bl printf + add w21, w21, 1 5: mov x0, x20 - mov x1, 5 - bl mod - cbnz x0, 10f - // If we get here, the counter was divisible by 5 - ldr x0, =buzz - bl printf - add w21, w21, 1 + mov x1, 5 + bl mod + cbnz x0, 10f + // If we get here, the counter was divisible by 5 + ldr x0, =buzz + bl printf + add w21, w21, 1 10: cbz w21, 20f - // If we get here, it means that we have printed - // something (either fizz, or buzz or fizzbuzz) - // so all we need now is a new line - ldr x0, =nl - bl puts - b 80f + // If we get here, it means that we have printed + // something (either fizz, or buzz or fizzbuzz) + // so all we need now is a new line + ldr x0, =nl + bl puts + b 80f 20: // If we get here, the counter was neither a - // multiple of 3 nor of 5. Therefore, we need - // to print the counter itself. + // multiple of 3 nor of 5. Therefore, we need + // to print the counter itself. - ldr x0, =fmt - mov x1, x20 - bl printf + ldr x0, =fmt + mov x1, x20 + bl printf 80: add x20, x20, 1 - b 1b + b 1b 99: ldr x21, [sp], 16 - ldp x20, x30, [sp], 16 - mov w0, wzr - ret + ldp x20, x30, [sp], 16 + mov w0, wzr + ret - .data + .data fizz: .asciz "Fizz" buzz: .asciz "Buzz" nl: .asciz "" fmt: .asciz "%ld\n" - .end + .end