// File: /workspace/github_c_makefile_star2_O2/theovosse[P]llgen/llgen.c
// Function: DetermineFollowRule
static void DetermineFollowRule(TREE *follow, Node rule, Name orig, TREE followers) {
	NodeList rules;
	TREE nFollowers;
	TREE chain1EltFollowers;
	TREE chain2EltFollowers;
    TREE sequenceFirstsAndFollowers;

	for (; rule != NULL; rule = rule->next) {
		if (rule->nodeType != single || rule->element.name == orig) {
			nFollowers = NULL;
			(void) collectFirst(&nFollowers, followers, rule->next);
			switch (rule->nodeType) {
				case single: /* && rule->element.name == orig */
					if (Unite(follow, nFollowers)) {
						changes = true;
					}
					break;
				case option:
					DetermineFollowRule(follow, rule->element.sub, orig, nFollowers);
					break;
				case sequence:
                    sequenceFirstsAndFollowers = NULL;
                    (void) collectFirst(&sequenceFirstsAndFollowers, NULL, rule->element.sub);
                    Unite(&sequenceFirstsAndFollowers, nFollowers);
					DetermineFollowRule(follow, rule->element.sub, orig, sequenceFirstsAndFollowers);
                    KillTree(sequenceFirstsAndFollowers, NULL);
					break;
				case chain:
					/*	A CHAIN B, C
						FOLLOW(A) = nFollowers + FIRST(B) + (EMPTY(B)? FIRST(A) + ...: EMPTY)
						FOLLOW(B) = FIRST(A) + (EMPTY(A)? FIRST(B) + nFollowers: EMPTY) */
					chain1EltFollowers = NULL;
					chain2EltFollowers = NULL;
					(void) collectFirst(&chain2EltFollowers, nFollowers, rule->element.sub->element.sub);
					/* chain2EltFollowers = FIRST(A) + (EMPTY(A)? nFollowers: EMPTY) */
					(void) collectFirst(&chain1EltFollowers, chain2EltFollowers, rule->element.sub->next->element.sub);
					/* chain1EltFollowers = FIRST(B) + (EMPTY(B)? chain2EltFollowers: EMPTY) */
					(void) Unite(&chain1EltFollowers, nFollowers);
					/* chain1EltFollowers = nFollowers + FIRST(B) + ... */
					DetermineFollowRule(follow, rule->element.sub->element.sub, orig, chain1EltFollowers);
					KillTree(chain1EltFollowers, NULL);
					KillTree(chain2EltFollowers, NULL);
					chain1EltFollowers = NULL;
					chain2EltFollowers = NULL;
					(void) collectFirst(&chain2EltFollowers, NULL, rule->element.sub->next->element.sub);
					/* chain2EltFollowers = FIRST(B) */
					(void) Unite(&chain2EltFollowers, nFollowers);
					/* chain2EltFollowers = FIRST(B) + nFollowers */
					(void) collectFirst(&chain1EltFollowers, chain2EltFollowers, rule->element.sub->element.sub);
					/* chain1EltFollowers = FIRST(A) + (EMPTY(A)? chain2EltFollowers: EMPTY) */
					DetermineFollowRule(follow, rule->element.sub->next->element.sub, orig, chain1EltFollowers);
					KillTree(chain1EltFollowers, NULL);
					KillTree(chain2EltFollowers, NULL);
					break;
				case alternative: /* Try each one... */
					for (rules = rule->element.alternatives; rules != NULL; rules = rules->rest) {
						DetermineFollowRule(follow, rules->first, orig, nFollowers);
					}
					break;
				case breakToken:
				case errorMessage:
					// Just empty productions
					break;
				// default:
				// 	fprintf(stderr, "DetermineFollowRule: unknown nodetype %d", rule->nodeType);
				// 	return;
			}
			KillTree(nFollowers, NULL);
		}
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movq %rcx, %rbx
movq %rdx, %r14
movq %rsi, %r15
movq %rdi, %r12
leaq 0x9ad3(%rip), %rbp      # 0x1006c
movq %rcx, 0x20(%rsp)
testq %r15, %r15
je 0x679e
cmpl $0x0, 0x4(%r15)
je 0x65fb
andq $0x0, (%rsp)
movq 0x28(%r15), %rdx
movq %rsp, %rdi
movq %rbx, %rsi
callq 0x6378
movl 0x4(%r15), %eax
cmpq $0x4, %rax
ja 0x678a
movslq (%rbp,%rax,4), %rax
addq %rbp, %rax
jmpq *%rax
movq (%rsp), %rsi
movq %r12, %rdi
callq 0x651d
testw %ax, %ax
je 0x678a
movb $0x1, 0x12532(%rip)     # 0x18b28
jmp 0x678a
cmpq %r14, 0x18(%r15)
jne 0x6795
jmp 0x65ae
leaq 0x18(%r15), %r13
movq (%r13), %r13
testq %r13, %r13
je 0x678a
movq (%r13), %rsi
movq (%rsp), %rcx
movq %r12, %rdi
movq %r14, %rdx
callq 0x6578
addq $0x8, %r13
jmp 0x660b
andq $0x0, 0x18(%rsp)
movq 0x18(%r15), %rdx
leaq 0x18(%rsp), %r13
movq %r13, %rdi
xorl %esi, %esi
callq 0x6378
movq (%rsp), %rsi
movq %r13, %rdi
callq 0x651d
movq 0x18(%r15), %rsi
movq 0x18(%rsp), %rcx
movq %r12, %rdi
movq %r14, %rdx
callq 0x6578
movq 0x18(%rsp), %rdi
jmp 0x676e
andq $0x0, 0x10(%rsp)
andq $0x0, 0x8(%rsp)
movq (%rsp), %rsi
movq 0x18(%r15), %rax
movq 0x18(%rax), %rdx
leaq 0x8(%rsp), %r13
movq %r13, %rdi
callq 0x6378
movq 0x8(%rsp), %rsi
movq 0x18(%r15), %rax
movq 0x28(%rax), %rax
movq 0x18(%rax), %rdx
movq %rbp, %rbx
leaq 0x10(%rsp), %rbp
movq %rbp, %rdi
callq 0x6378
movq (%rsp), %rsi
movq %rbp, %rdi
callq 0x651d
movq 0x18(%r15), %rax
movq 0x18(%rax), %rsi
movq 0x10(%rsp), %rcx
movq %r12, %rdi
movq %r14, %rdx
callq 0x6578
movq 0x10(%rsp), %rdi
xorl %esi, %esi
callq 0xb397
movq 0x8(%rsp), %rdi
xorl %esi, %esi
callq 0xb397
andq $0x0, 0x10(%rsp)
andq $0x0, 0x8(%rsp)
movq 0x18(%r15), %rax
movq 0x28(%rax), %rax
movq 0x18(%rax), %rdx
movq %r13, %rdi
xorl %esi, %esi
callq 0x6378
movq (%rsp), %rsi
movq %r13, %rdi
callq 0x651d
movq 0x8(%rsp), %rsi
movq 0x18(%r15), %rax
movq 0x18(%rax), %rdx
movq %rbp, %rdi
movq %rbx, %rbp
movq 0x20(%rsp), %rbx
callq 0x6378
movq 0x18(%r15), %rax
movq 0x28(%rax), %rax
movq 0x18(%rax), %rsi
movq 0x10(%rsp), %rcx
movq %r12, %rdi
movq %r14, %rdx
callq 0x6578
movq 0x10(%rsp), %rdi
xorl %esi, %esi
callq 0xb397
movq 0x8(%rsp), %rdi
xorl %esi, %esi
callq 0xb397
jmp 0x678a
movq 0x18(%r15), %rsi
movq (%rsp), %rcx
movq %r12, %rdi
movq %r14, %rdx
callq 0x6578
movq (%rsp), %rdi
xorl %esi, %esi
callq 0xb397
movq 0x28(%r15), %r15
jmp 0x659e
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq