about summary refs log blame commit diff stats
path: root/apps/subx-common.subx
blob: 3b55829dcd8b0a1f4b32eaa86918f20bec615bb7 (plain) (tree)
1
2
3
4
5
6
7
8
                                                        
 
                                                



                                         
                    


                                  
                     


                                                              
                    
 

                                                   
                              
 




                                                                                                                                                 



                                                                 

                                                                                                                                                                       
                      







                                                                                                                                                                             


                                    
                                                                                                                                                                     


                                       
                                                                                                                                                                  

                                                         



                                                                                                                                                                             

                                                         

                                                                                                                                                                        


                                          


                                                                                                                                                                              
                                                                                                             


                                                                                                                                                                                        
               
                                        


                                                       


                                                                                                                                                                              
                                
                                                                                                                                                                            




                                                                                      
                                                                                                                                                                     


                                                      
                                                                                                                                                                  
                                        


                                                                                                                                                                              

                         



                 
              

                                                                                                                                                                       



               

                                                                                                                                                                       






                                  

                                                                                                                                                                  

                          
                                                                                                                                                                       






                                 
                                                                                                                                                                  

                                    
               



                               
                                                                                                                                                                  





                                                                 


                                                                                                                                                                          


                                    
                                                                                                                                                                  





                                                               


                                                                                                                                                                            


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                     

                                                                                                                                                                       






                                  

                                                                                                                                                                  

                          
                                                                                                                                                                       






                                  
                                                                                                                                                                  

                                    
               



                               
                                                                                                                                                                  





                                                                    


                                                                                                                                                                          


                                    
                                                                                                                                                                  





                                                                  


                                                                                                                                                                            


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                           

                                                                                                                                                                       






                                  

                                                                                                                                                                  

                          
                                                                                                                                                                       


                                    
               



                               
                                                                                                                                                                  




                                                                   


                                                                                                                                                                              


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       

             



                                                                        

                                                                                                                                                                       
                      





                                                                                                                                                                            
                                       


                                                                                                                                                                              
                                      


                                                                                                                                                                              


                                        




                                                                                                                                                                             

                         


                 
              

                                                                                                                                                                       



                 

                                                                                                                                                                       






                                        
                                                                                                                                                                  







                                                
                                                                                                                                                                  



                                                      

                                                                                                                                                                     


                                    
                                                                                                                                                                  





                                     
                                                                                                                                                                  



                                          

                                                                                                                                                                     


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                

                                                                                                                                                                       






                                        
                                                                                                                                                                  







                                               
                                                                                                                                                                  



                                                                     

                                                                                                                                                                     


                                    
                                                                                                                                                                  





                                     
                                                                                                                                                                  



                                                        

                                                                                                                                                                     


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                 

                                                                                                                                                                       






                                        
                                                                                                                                                                  







                                                  
                                                                                                                                                                  



                                                                      

                                                                                                                                                                     


                                    
                                                                                                                                                                  





                                     
                                                                                                                                                                  



                                                         

                                                                                                                                                                     


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                       

                                                                                                                                                                       






                                        
                                                                                                                                                                  







                                                    
                                                                                                                                                                  
                                   
                                                                                                                                                                        





                                     
                                                                                                                                                                  



                                                               

                                                                                                                                                                     


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       

             
                                                                                    
              

                                                                                                                                                                       
                      








                                                                                                                                                                             
                         
                    

                                  
                                                                                                                                                                            

                                                                                 
                                                                                                                                                                               
                             

                                               

                                                       

                                            

                                                              
                    

                               
                    


                                             
                    

                                  
                                                                                                                                                                       

                          


                 
              

                                                                                                                                                                       



                          










                                                                                                                                                                             


                                        

                                                                                                                                                                  


                                                  


                                                                                                                                                                             


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                         










                                                                                                                                                                             


                                        

                                                                                                                                                                  


                                                                 


                                                                                                                                                                             


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                          










                                                                                                                                                                             


                                        

                                                                                                                                                                  


                                                                  


                                                                                                                                                                             


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                       










                                                                                                                                                                             


                                        

                                                                                                                                                                  


                                                               


                                                                                                                                                                             


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       

             

                                                      
                                                                     



                                                                                          

                                                                                                                                                                       
                      





                                                                                                                                                                             
                               


                                                                                                                                                                              
                    



                                                                                                                                                                          
                                    
                   

                                                                                                                                                                     
              
                                        
                      
                                                                                                                                                                  

                       
                                                                                                                                                                  
                         


                 
              

                                                                                                                                                                       



                       

                                                                                                                                                                       






                                         
                                                                                                                                                                  

                                                  


                                                    


                                
                                                                                                                                                                  





                                        
                                                                                                                                                                  







                                         
                                                                                                                                                                  






                                                                       
                                                                                                                                                                  






                                               
                                                                                                                                                                  







                                                            
                                                                                                                                                                  
              

                                                                                                                                                                       

             
                                                                               








                                                                                           
              

                                                                                                                                                                       
                      








                                                                                                                                                                            

                          
                                                                                                                                                                       

                                                              
               
                             

                                                                                                                                                                 


                                         


                                                                                                                                                                            


                                                       
               
                             

               


                                         
                                                                                                                                                                  
                                          
                                
                   
               


                                


                                                                                                                                                                  

                                                    
                                   
                   

                                                                                                                                                                      


                                


                                                                                                                                                                  

                                                   
                                                                                                                                                                            

                                      
                                

                                     
                                 

                      
                                                                                                                                                                  
                         



                 
              

                                                                                                                                                                       
             
 

                       











                                                                                                                                                                             

                          
               


                                 

                                                                                                                                                                  


                                               
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                        











                                                                                                                                                                             

                      
               


                                 

                                                                                                                                                                  


                                                
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                              











                                                                                                                                                                             

                      
               


                                 

                                                                                                                                                                  


                                                      
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                











                                                                                                                                                                             

                      
               


                                 

                                                                                                                                                                  


                                                        
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                 











                                                                                                                                                                             

                      
               


                                 

                                                                                                                                                                  


                                                         
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       

             





                                                                                     

                                                                                                                                                                       
                      





                                                                                                                                                                             

                          
                                                                                                                                                                       

                                                                
               
                             

                                                                                                                                                                     


                                         
                                                                                                                                                                  
                                                                           
                                  
                   
               


                                  


                                                                                                                                                                  



                                         

                                                                                                                                                                     


                                        
                                                                                                                                                                  


                                
                                                                                                                                                                     


                                  
                                                                                                                                                                  







                                                                               
                                        
                   
               


                                 
                                                                                                                                                                  

                                   


                                                                                                                                                                      


                            
                                                                                                                                                                  

                      
                                                                                                                                                                  
                         


                 
              

                                                                                                                                                                       



                 

                                                                                                                                                                       






                                         
                                                                                                                                                                  

                                                  


                                                    


                                









                                                                                                                                                                             


                                                
               



                                             
                                                                                                                                                                  





                                             
                                                                                                                                                                  







                                                         
                                                                                                                                                                  
              

                                                                                                                                                                       




                                                      

                                                                                                                                                                       






                                         
                                                                                                                                                                  

                                                  


                                                    


                                









                                                                                                                                                                             


                                                
               



                                             
                                                                                                                                                                  





                                             
                                                                                                                                                                  







                                                            
                                                                                                                                                                  
              

                                                                                                                                                                       



                               

                                                                                                                                                                       






                                         
                                                                                                                                                                  

                                                  


                                                    


                                









                                                                                                                                                                             


                                                
               



                                             
                                                                                                                                                                  





                                             
                                                                                                                                                                  








                                                            
                                                                                                                                                                  
              

                                                                                                                                                                       



                     

                                                                                                                                                                       






                                         
                                                                                                                                                                  

                                                  


                                                    


                                









                                                                                                                                                                             


                                                
               



                                             
                                                                                                                                                                  





                                             
                                                                                                                                                                  







                                                         
                                                                                                                                                                  
              

                                                                                                                                                                       



                                   

                                                                                                                                                                       






                                         
                                                                                                                                                                  

                                                  


                                                    


                                









                                                                                                                                                                             


                                                
               



                                             
                                                                                                                                                                  





                                             
                                                                                                                                                                  







                                                           
                                                                                                                                                                  
              

                                                                                                                                                                       



                                                      

                                                                                                                                                                       






                                         
                                                                                                                                                                  

                                                  


                                                    


                                









                                                                                                                                                                             


                                                
               



                                             
                                                                                                                                                                  





                                             
                                                                                                                                                                  







                               
                                                                                                                                                                     






                                                      
                                                                                                                                                                     






                                 
                                                                                                                                                                     








                                                                 
                                                                                                                                                                  
              

                                                                                                                                                                       









                                                                               
                                                        
              

                                                                                                                                                                       
                      







                                                                                                                                                                            

                                    
                                                                                                                                                                            
                                                                     
                       



                                                                                                                                                                             

                                                 


                                                                                                                                                                               
                                
                                  


                                                 
                                   


                                                 
                                   


                                                  
                                 


                                      
                                

                         

                 
              

                                                                                                                                                                       



                                













                                                                                                                                                                             


                                  

                                                                                                                                                                  


                                                        
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                   













                                                                                                                                                                             


                                  

                                                                                                                                                                  


                                                           
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                             













                                                                                                                                                                             


                                  

                                                                                                                                                                  


                                                     
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                         













                                                                                                                                                                             


                                  

                                                                                                                                                                  


                                                                 
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                          













                                                                                                                                                                             


                                  

                                                                                                                                                                  


                                                                  
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       



                                     













                                                                                                                                                                             


                                  

                                                                                                                                                                  


                                                             
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       




                                                                                        

                                                                                                                                                                       
                      












                                                                                                                                                                             

                              
                                                                                                                                                                            
                                                    
                                   
                   

               


                                       
                                                                                                                                                                  


                                   
               


                                       


                                                                                                                                                                                                       

                   
                    


                                 




                 
              

                                                                                                                                                                       









                                         
                                                                                                                                                                  

                                                  


                                                    


                                
                                                                                                                                                                  







                                                   
                                                                                                                                                                  





                                             
                                                                                                                                                                  




                                                              

                                                                                                                                                                      


                                    
                                                                                                                                                                  










                                         
                                                                                                                                                                  

                                                  


                                                    


                                
                                                                                                                                                                  







                                                     
                                                                                                                                                                  





                                             
                                                                                                                                                                  







                                                            
                                                                                                                                                                  










                                         
                                                                                                                                                                  

                                                  


                                                    


                                
                                                                                                                                                                  







                                                   
                                                                                                                                                                  





                                             
                                                                                                                                                                  







                                                  
                                                                                                                                                                  










                                         
                                                                                                                                                                  

                                                  


                                                    


                                
                                                                                                                                                                  







                                                 
                                                                                                                                                                  





                                             
                                                                                                                                                                  







                                                         
                                                                                                                                                                  


             


                                                                                      

                                                                                                                                                                       
                      














                                                                                                                                                                             

                              
                                                                                                                                                                            



                                                                   


                                                                                                                                                                               


                            
                                                                                                                                                                  
            
                    


                                       



                 
              

                                                                                                                                                                       



                    

                                                                                                                                                                       






                                         
                                                                                                                                                                  

                                                  


                                                    


                                

                                                                                                                                                                  

                                               
                                                                                                                                                                       

                                                     
               



                                             
                                                                                                                                                                  





                                             
                                                                                                                                                                  







                                       
                                                                                                                                                                     






                                                      
                                                                                                                                                                     






                                 
                                                                                                                                                                     





                                             
                                                                                                                                                                     








                                                                         
                                                                                                                                                                  
              

                                                                                                                                                                       

             
                                                         
              

                                                                                                                                                                       
                      














                                                                                                                                                                             

                                          
                      
                                                                                                                                                                  
                   
                      
                                                                                                                                                                  
                         
                 
              

                                                                                                                                                                       

             
                                                          
              

                                                                                                                                                                       
                      


                                                                                                                                                                            
                                                
                                          
                   
                          
               
              

                                 



                                                                                                                                                                  
                                                           
                                                 
                                           
                   
                           
               
              

                                 



                                                                                                                                                                  
                                                           
                                                
                                          
                   
                          
               
              

                                 



                                                                                                                                                                  
                                                           
                                                 
                                           
                   
                           
               
              

                                 



                                                                                                                                                                  
                                                           
                        
                           

                            
                 
              

                                                                                                                                                                       

             

                   

                                                                                                                                                                       
                         
                                     


                             
                                 
                      

                                                                                                                                                                  

                                                     
               

                    
                                    
                      
                                                                                                                                                                  
                          
                                    


                            
                                 
                      

                                                                                                                                                                  

                                                    
               

                    
                                    
                      
                                                                                                                                                                  
                          
                                    


                            
                                 
                      

                                                                                                                                                                  

                                                    
               

                    
                                    
                      
                                                                                                                                                                  
                          
                                      


                              
                                 
                      

                                                                                                                                                                  

                                                      
               

                    
                                    
                      
                                                                                                                                                                  
                           
                                       


                               
                                 
                      

                                                                                                                                                                  

                                                       
               

                    
                                    
                      
                                                                                                                                                                  
                           
                                       


                               
                                 
                      

                                                                                                                                                                  

                                                       
               

                    
                                    
                      
                                                                                                                                                                  
                                
                               


                       
                                 
                      

                                                                                                                                                                  

                                                             
               

                    
                                    
                      
                                                                                                                                                                  
              

                                                                                                                                                                       

             
                                                    
              

                                                                                                                                                                       
                      




                                                                                                                                                                            
                                    






                                                                                                                                                                                    
                                          
                                 

                         
                 
              

                                                                                                                                                                       



               

                                                                                                                                                                       
                     











                                                                                                                                                                             
              
                             
                      

                                                                                                                                                                  


                                            
               


                                    
                                                                                                                                                                  
                      











                                                                                                                                                                             
              
                             
                      

                                                                                                                                                                  


                                             
               


                                    
                                                                                                                                                                  
              

                                                                                                                                                                       

             

       



                       
                            
# common helpers shared by phases of the SubX translator

# - some limits on the programs we can translate
== data

# maximum memory available for allocation
Heap-size:
  0x200000/imm32/2MB

# maximum size of a single segment
Segment-size:
  0x80000/imm32/512KB

# maximum size of input textual stream (spanning all segments)
Input-size:
  0x100000/imm32/1MB

# maximum size of the 'labels' table in survey.subx
Max-labels:
  0x10000/imm32/4K-labels/64KB

== code
#   instruction                     effective address                                                   register    displacement    immediate
# . op          subop               mod             rm32          base        index         scale       r32
# . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes

# (re)compute the bounds of the next word in the line
# return empty string on reaching end of file
next-word:  # line : (address stream byte), out : (address slice)
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    57/push-edi
    # esi = line
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
    # edi = out
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
    # skip-chars-matching(line, ' ')
    # . . push args
    68/push  0x20/imm32/space
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  skip-chars-matching/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
$next-word:check0:
    # if (line->read >= line->write) clear out and return
    # . eax = line->read
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy *(esi+4) to eax
    # . if (eax < line->write) goto next check
    3b/compare                      0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # compare eax with *esi
    7c/jump-if-lesser  $next-word:check-for-comment/disp8
    # . return out = {0, 0}
    c7          0/subop/copy        0/mod/direct    7/rm32/edi    .           .             .           .           .               0/imm32           # copy to *edi
    c7          0/subop/copy        1/mod/*+disp8   7/rm32/edi    .           .             .           .           4/disp8         0/imm32           # copy to *(edi+4)
    eb/jump  $next-word:end/disp8
$next-word:check-for-comment:
    # out->start = &line->data[line->read]
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   0xc/disp8       .                 # copy esi+ecx+12 to eax
    89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # copy eax to *edi
    # if (line->data[line->read] == '#') out->end = &line->data[line->write]), skip rest of stream and return
    # . eax = line->data[line->read]
    31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
    8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(esi+ecx+12) to AL
    # . compare
    3d/compare-eax-and  0x23/imm32/pound
    75/jump-if-not-equal  $next-word:regular-word/disp8
$next-word:comment:
    # . out->end = &line->data[line->write]
    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  0/index/eax   .           0/r32/eax   0xc/disp8       .                 # copy esi+eax+12 to eax
    89/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(edi+4)
    # . line->read = line->write
    89/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(esi+4)
    # . return
    eb/jump  $next-word:end/disp8
$next-word:regular-word:
    # otherwise skip-chars-not-matching-whitespace(line)  # including trailing newline
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  skip-chars-not-matching-whitespace/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # out->end = &line->data[line->read]
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/eax   0xc/disp8       .                 # copy esi+ecx+12 to eax
    89/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(edi+4)
$next-word:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-next-word:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # var slice/ecx = {0, 0}
    68/push  0/imm32/end
    68/push  0/imm32/start
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # write(_test-stream, "  ab")
    # . . push args
    68/push  "  ab"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # next-word(_test-stream, slice)
    # . . push args
    51/push-ecx
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-word/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(slice->start - _test-stream->data, 2, msg)
    # . check-ints-equal(slice->start - _test-stream, 14, msg)
    # . . push args
    68/push  "F - test-next-word: start"/imm32
    68/push  0xe/imm32
    # . . push slice->start - _test-stream
    8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
    81          5/subop/subtract    3/mod/direct    0/rm32/eax    .           .             .           .           .               _test-stream/imm32 # subtract from eax
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # check-ints-equal(slice->end - _test-stream->data, 4, msg)
    # . check-ints-equal(slice->end - _test-stream, 16, msg)
    # . . push args
    68/push  "F - test-next-word: end"/imm32
    68/push  0x10/imm32
    # . . push slice->end - _test-stream
    8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
    81          5/subop/subtract    3/mod/direct    0/rm32/eax    .           .             .           .           .               _test-stream/imm32 # subtract from eax
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-next-word-returns-whole-comment:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # var slice/ecx = {0, 0}
    68/push  0/imm32/end
    68/push  0/imm32/start
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # write(_test-stream, "  # a")
    # . . push args
    68/push  "  # a"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # next-word(_test-stream, slice)
    # . . push args
    51/push-ecx
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-word/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(slice->start - _test-stream->data, 2, msg)
    # . check-ints-equal(slice->start - _test-stream, 14, msg)
    # . . push args
    68/push  "F - test-next-word-returns-whole-comment: start"/imm32
    68/push  0xe/imm32
    # . . push slice->start - _test-stream
    8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
    81          5/subop/subtract    3/mod/direct    0/rm32/eax    .           .             .           .           .               _test-stream/imm32 # subtract from eax
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # check-ints-equal(slice->end - _test-stream->data, 5, msg)
    # . check-ints-equal(slice->end - _test-stream, 17, msg)
    # . . push args
    68/push  "F - test-next-word-returns-whole-comment: end"/imm32
    68/push  0x11/imm32
    # . . push slice->end - _test-stream
    8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
    81          5/subop/subtract    3/mod/direct    0/rm32/eax    .           .             .           .           .               _test-stream/imm32 # subtract from eax
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-next-word-returns-empty-string-on-eof:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # var slice/ecx = {0, 0}
    68/push  0/imm32/end
    68/push  0/imm32/start
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # write nothing to _test-stream
    # next-word(_test-stream, slice)
    # . . push args
    51/push-ecx
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-word/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(slice->end - slice->start, 0, msg)
    # . . push args
    68/push  "F - test-next-word-returns-empty-string-on-eof"/imm32
    68/push  0/imm32
    # . . push slice->end - slice->start
    8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
    2b/subtract                     0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract *ecx from eax
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

# update line->read to end of string literal surrounded by double quotes
# line->read must start out at a double-quote
skip-string:  # line : (address stream)
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    # ecx = line
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
    # eax = skip-string-in-slice(&line->data[line->read], &line->data[line->write])
    # . . push &line->data[line->write]
    8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .                         2/r32/edx   8/disp8         .                 # copy *(ecx+8) to edx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   0xc/disp8       .                 # copy ecx+edx+12 to edx
    52/push-edx
    # . . push &line->data[line->read]
    8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .                         2/r32/edx   4/disp8         .                 # copy *(ecx+4) to edx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    1/base/ecx  2/index/edx   .           2/r32/edx   0xc/disp8       .                 # copy ecx+edx+12 to edx
    52/push-edx
    # . . call
    e8/call  skip-string-in-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # line->read = eax - line->data
    29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
    2d/subtract-from-eax  0xc/imm32
    89/copy                         1/mod/*+disp8   1/rm32/ecx    .           .                         0/r32/eax   4/disp8         .                 # copy eax to *(ecx+4)
$skip-string:end:
    # . restore registers
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-skip-string:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . write(_test-input-stream, "\"abc\" def")
    # .                   indices:  0123 45
    # . . push args
    68/push  "\"abc\" def"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # precondition: line->read == 0
    # . . push args
    68/push  "F - test-skip-string/precondition"/imm32
    68/push  0/imm32
    b8/copy-to-eax  _test-input-stream/imm32
    ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # skip-string(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  skip-string/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(line->read, 5, msg)
    # . . push args
    68/push  "F - test-skip-string"/imm32
    68/push  5/imm32
    b8/copy-to-eax  _test-input-stream/imm32
    ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-skip-string-ignores-spaces:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . write(_test-input-stream, "\"a b\"/yz")
    # .                   indices:  0123 45
    # . . push args
    68/push  "\"a b\"/yz"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # precondition: line->read == 0
    # . . push args
    68/push  "F - test-skip-string-ignores-spaces/precondition"/imm32
    68/push  0/imm32
    b8/copy-to-eax  _test-input-stream/imm32
    ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # skip-string(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  skip-string/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(line->read, 5, msg)
    # . . push args
    68/push  "F - test-skip-string-ignores-spaces"/imm32
    68/push  5/imm32
    b8/copy-to-eax  _test-input-stream/imm32
    ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-skip-string-ignores-escapes:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . write(_test-input-stream, "\"a\\\"b\"/yz")
    # .                   indices:  01 2 34 56
    # . . push args
    68/push  "\"a\\\"b\"/yz"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # precondition: line->read == 0
    # . . push args
    68/push  "F - test-skip-string-ignores-escapes/precondition"/imm32
    68/push  0/imm32
    b8/copy-to-eax  _test-input-stream/imm32
    ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # skip-string(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  skip-string/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(line->read, 6, msg)
    # . . push args
    68/push  "F - test-skip-string-ignores-escapes"/imm32
    68/push  6/imm32
    b8/copy-to-eax  _test-input-stream/imm32
    ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-skip-string-works-from-mid-stream:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . write(_test-input-stream, "0 \"a\\\"b\"/yz")
    # .                   indices:  01 2 34 56
    # . . push args
    68/push  "0 \"a\\\"b\"/yz"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # precondition: line->read == 2
    c7          0/subop/copy        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         2/imm32           # copy to *(eax+4)
    # skip-string(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  skip-string/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(line->read, 8, msg)
    # . . push args
    68/push  "F - test-skip-string-works-from-mid-stream"/imm32
    68/push  8/imm32
    b8/copy-to-eax  _test-input-stream/imm32
    ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

skip-string-in-slice:  # curr : (address byte), end : (address byte) -> new_curr/eax
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    51/push-ecx
    52/push-edx
    53/push-ebx
    # ecx = curr
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
    # edx = end
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         2/r32/edx   0xc/disp8         .               # copy *(ebp+12) to edx
    # eax = 0
    31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
    # skip initial dquote
    41/increment-ecx
$skip-string-in-slice:loop:
    # if (curr >= end) return curr
    39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
    73/jump-if-greater-unsigned-or-equal  $skip-string-in-slice:return-curr/disp8
    # AL = *curr
    8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
$skip-string-in-slice:dquote:
    # if (eax == '"') break
    3d/compare-eax-and  0x22/imm32/double-quote
    74/jump-if-equal  $skip-string-in-slice:break/disp8
$skip-string-in-slice:check-for-escape:
    # if (eax == '\') escape next char
    3d/compare-eax-and  0x5c/imm32/backslash
    75/jump-if-not-equal  $skip-string-in-slice:continue/disp8
$skip-string-in-slice:escape:
    41/increment-ecx
$skip-string-in-slice:continue:
    # ++curr
    41/increment-ecx
    eb/jump  $skip-string-in-slice:loop/disp8
$skip-string-in-slice:break:
    # skip final dquote
    41/increment-ecx
$skip-string-in-slice:return-curr:
    # return curr
    89/copy                         3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to eax
$skip-string-in-slice:end:
    # . restore registers
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-skip-string-in-slice:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup: (eax..ecx) = "\"abc\" def"
    b8/copy-to-eax  "\"abc\" def"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # eax = skip-string-in-slice(eax, ecx)
    # . . push args
    51/push-ecx
    50/push-eax
    # . . call
    e8/call  skip-string-in-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(ecx-eax, 4, msg)  # number of chars remaining after the string literal
    # . . push args
    68/push  "F - test-skip-string-in-slice"/imm32
    68/push  4/imm32
    # . . push ecx-eax
    29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
    51/push-ecx
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-skip-string-in-slice-ignores-spaces:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup: (eax..ecx) = "\"a b\"/yz"
    b8/copy-to-eax  "\"a b\"/yz"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # eax = skip-string-in-slice(eax, ecx)
    # . . push args
    51/push-ecx
    50/push-eax
    # . . call
    e8/call  skip-string-in-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(ecx-eax, 3, msg)  # number of chars remaining after the string literal
    # . . push args
    68/push  "F - test-skip-string-in-slice-ignores-spaces"/imm32
    68/push  3/imm32
    # . . push ecx-eax
    29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
    51/push-ecx
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-skip-string-in-slice-ignores-escapes:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup: (eax..ecx) = "\"a\\\"b\"/yz"
    b8/copy-to-eax  "\"a\\\"b\"/yz"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # eax = skip-string-in-slice(eax, ecx)
    # . . push args
    51/push-ecx
    50/push-eax
    # . . call
    e8/call  skip-string-in-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(ecx-eax, 3, msg)  # number of chars remaining after the string literal
    # . . push args
    68/push  "F - test-skip-string-in-slice-ignores-escapes"/imm32
    68/push  3/imm32
    # . . push ecx-eax
    29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
    51/push-ecx
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-skip-string-in-slice-stops-at-end:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup: (eax..ecx) = "\"abc"  # unbalanced dquote
    b8/copy-to-eax  "\"abc"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # eax = skip-string-in-slice(eax, ecx)
    # . . push args
    51/push-ecx
    50/push-eax
    # . . call
    e8/call  skip-string-in-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(ecx-eax, 0, msg)  # skipped to end of slice
    # . . push args
    68/push  "F - test-skip-string-in-slice-stops-at-end"/imm32
    68/push  0/imm32
    # . . push ecx-eax
    29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
    51/push-ecx
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

# write an entire stream's contents to a buffered-file
# ways to do this:
#   - construct a 'maximal slice' and pass it to write-slice-buffered
#   - flush the buffered-file and pass the stream directly to its fd (disabling buffering)
# we'll go with the first way for now
write-stream-data:  # f : (address buffered-file), s : (address stream) -> <void>
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    # esi = s
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
    # var slice/ecx = {s->data, s->data + s->write}
    # . push s->data + s->write
    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  0/index/eax   .           0/r32/eax   0xc/disp8       .                 # copy esi+eax+12 to eax
    50/push-eax
    # . push s->data
    8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   0xc/disp8       .                 # copy esi+12 to eax
    50/push-eax
    # . ecx = esp
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # write-slice-buffered(f, slice)
    # . . push args
    51/push-ecx
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  write-slice-buffered/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
$write-stream-data:end:
    # . restore locals
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . restore registers
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-write-stream-data:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # initialize input
    # . write(_test-input-stream, "abcd")
    # . . push args
    68/push  "abcd"/imm32
    68/push  _test-input-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write-stream-data(_test-output-buffered-file, _test-input-stream)
    # . . push args
    68/push  _test-input-stream/imm32
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  write-stream-data/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check that the write happened as expected
    # . flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . check-stream-equal(_test-output-stream, "abcd", msg)
    # . . push args
    68/push  "F - test-write-stream-data"/imm32
    68/push  "abcd"/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-stream-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

has-metadata?:  # word : (address slice), s : (address string) -> eax : boolean
    # pseudocode:
    #   var twig : &slice = next-token-from-slice(word->start, word->end, '/')  # skip name
    #   curr = twig->end
    #   while true
    #     twig = next-token-from-slice(curr, word->end, '/')
    #     if (twig.empty()) break
    #     if (slice-equal?(twig, s)) return true
    #     curr = twig->end
    #   return false
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    51/push-ecx
    52/push-edx
    56/push-esi
    57/push-edi
    # esi = word
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
    # edx = word->end
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           2/r32/edx   4/disp8         .                 # copy *(esi+4) to edx
    # var twig/edi : (address slice) = {0, 0}
    68/push  0/imm32/end
    68/push  0/imm32/start
    89/copy                         3/mod/direct    7/rm32/edi    .           .             .           4/r32/esp   .               .                 # copy esp to edi
    # next-token-from-slice(word->start, word->end, '/', twig)
    # . . push args
    57/push-edi
    68/push  0x2f/imm32/slash
    52/push-edx
    ff          6/subop/push        0/mod/indirect  6/rm32/esi    .           .             .           .           .               .                 # push *esi
    # . . call
    e8/call  next-token-from-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
    # curr/ecx = twig->end
    8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(edi+4) to ecx
$has-metadata?:loop:
    # next-token-from-slice(curr, word->end, '/', twig)
    # . . push args
    57/push-edi
    68/push  0x2f/imm32/slash
    52/push-edx
    51/push-ecx
    # . . call
    e8/call  next-token-from-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
    # if (slice-empty?(twig)) return false
    # . eax = slice-empty?(twig)
    # . . push args
    57/push-edi
    # . . call
    e8/call  slice-empty?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . if (eax != 0) return false
    3d/compare-eax-and  0/imm32
    75/jump-if-not-equal  $has-metadata?:false/disp8
    # if (slice-equal?(twig, s)) return true
    # . eax = slice-equal?(twig, s)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    57/push-edi
    # . . call
    e8/call  slice-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax != 0) return true
    3d/compare-eax-and  0/imm32
    75/jump-if-not-equal  $has-metadata?:true/disp8
    # curr = twig->end
    8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(edi+4) to ecx
    eb/jump  $has-metadata?:loop/disp8
$has-metadata?:true:
    b8/copy-to-eax  1/imm32/true
    eb/jump  $has-metadata?:end/disp8
$has-metadata?:false:
    b8/copy-to-eax  0/imm32/false
$has-metadata?:end:
    # . reclaim locals
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-has-metadata-true:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # (eax..ecx) = "ab/imm32"
    b8/copy-to-eax  "ab/imm32"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var in/esi : (address slice) = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    6/rm32/esi    .           .             .           4/r32/esp   .               .                 # copy esp to esi
    # eax = has-metadata?(esi, "imm32")
    # . . push args
    68/push  "imm32"/imm32
    56/push-esi
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 1, msg)
    # . . push args
    68/push  "F - test-has-metadata-true"/imm32
    68/push  1/imm32/true
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-has-metadata-false:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # (eax..ecx) = "ab/c"
    b8/copy-to-eax  "ab/c"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var in/esi : (address slice) = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    6/rm32/esi    .           .             .           4/r32/esp   .               .                 # copy esp to esi
    # eax = has-metadata?(esi, "d")
    # . . push args
    68/push  "d"/imm32
    56/push-esi
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-has-metadata-false"/imm32
    68/push  0/imm32/false
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-has-metadata-ignore-name:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # (eax..ecx) = "a/b"
    b8/copy-to-eax  "a/b"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var in/esi : (address slice) = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    6/rm32/esi    .           .             .           4/r32/esp   .               .                 # copy esp to esi
    # eax = has-metadata?(esi, "a")
    # . . push args
    68/push  "a"/imm32
    56/push-esi
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-has-metadata-ignore-name"/imm32
    68/push  0/imm32/false
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-has-metadata-multiple-true:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # (eax..ecx) = "a/b/c"
    b8/copy-to-eax  "a/b/c"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var in/esi : (address slice) = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    6/rm32/esi    .           .             .           4/r32/esp   .               .                 # copy esp to esi
    # eax = has-metadata?(esi, "c")
    # . . push args
    68/push  "c"/imm32
    56/push-esi
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 1, msg)
    # . . push args
    68/push  "F - test-has-metadata-multiple-true"/imm32
    68/push  1/imm32/true
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-has-metadata-multiple-false:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # (eax..ecx) = "a/b/c"
    b8/copy-to-eax  "a/b/c"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var in/esi : (address slice) = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    6/rm32/esi    .           .             .           4/r32/esp   .               .                 # copy esp to esi
    # eax = has-metadata?(esi, "d")
    # . . push args
    68/push  "d"/imm32
    56/push-esi
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-has-metadata-multiple-false"/imm32
    68/push  0/imm32/false
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

# If datum of 'word' is not a valid name, it must be a hex int. Parse and print
# it in 'width' bytes of hex, least significant first.
# Otherwise just print the entire word including metadata.
# Always print a trailing space.
emit:  # out : (address buffered-file), word : (address slice), width : int -> <void>
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    56/push-esi
    57/push-edi
    # esi = word
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
    # var name/edi : (address slice) = {0, 0}
    68/push  0/imm32/end
    68/push  0/imm32/start
    89/copy                         3/mod/direct    7/rm32/edi    .           .             .           4/r32/esp   .               .                 # copy esp to edi
    # datum = next-token-from-slice(word->start, word->end, '/')
    # . . push args
    57/push-edi
    68/push  0x2f/imm32/slash
    ff          6/subop/push        1/mod/*+disp8   6/rm32/esi    .           .             .           .           4/disp8         .                 # push *(esi+4)
    ff          6/subop/push        0/mod/indirect  6/rm32/esi    .           .             .           .           .               .                 # push *esi
    # . . call
    e8/call  next-token-from-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
    # if (is-valid-name?(datum)) write-slice-buffered(out, word) and return
    # . eax = is-valid-name?(name)
    # . . push args
    57/push-edi
    # . . call
    e8/call  is-valid-name?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . if (eax != 0)
    3d/compare-eax-and  0/imm32
    74/jump-if-equal  $emit:hex-int/disp8
$emit:name:
    # . write-slice-buffered(out, word)
    # . . push args
    56/push-esi
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  write-slice-buffered/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . write-buffered(out, " ")
    # . . push args
    68/push  " "/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  write-buffered/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . return
    eb/jump  $emit:end/disp8
    # otherwise emit-hex(out, parse-hex-int(datum), width)
    #   (Weird shit can happen here if the datum of 'word' isn't either a valid
    #   name or a hex number, but we're only going to be passing in real legal
    #   programs. We just want to make sure that valid names aren't treated as
    #   (valid) hex numbers.)
$emit:hex-int:
    # . value/eax = parse-hex-int(datum)
    # . . push args
    57/push-edi
    # . . call
    e8/call  parse-hex-int/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . emit-hex(out, value, width)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
    50/push-eax
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  emit-hex/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
$emit:end:
    # . reclaim locals
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    58/pop-to-eax
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-emit-number:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # (eax..ecx) = "30"
    b8/copy-to-eax  "30"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var slice/ecx = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # emit(_test-output-buffered-file, slice, 1)
    # . . push args
    68/push  1/imm32
    51/push-ecx
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  emit/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-stream-equal(_test-output-stream, "30 ", msg)
    # . . push args
    68/push  "F - test-emit-number/1"/imm32
    68/push  "30 "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-stream-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-emit-negative-number:
    # test support for sign-extending negative numbers
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # (eax..ecx) = "-2"
    b8/copy-to-eax  "-2"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var slice/ecx = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # emit(_test-output-buffered-file, slice, 2)
    # . . push args
    68/push  2/imm32
    51/push-ecx
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  emit/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-stream-equal(_test-output-stream, "fe ff ", msg)
    # . . push args
    68/push  "F - test-emit-number/1"/imm32
    68/push  "fe ff "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-stream-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-emit-number-with-metadata:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # (eax..ecx) = "-2/foo"
    b8/copy-to-eax  "-2/foo"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var slice/ecx = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # emit(_test-output-buffered-file, slice, 2)
    # . . push args
    68/push  2/imm32
    51/push-ecx
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  emit/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # the '/foo' will have no impact on the output
    # check-stream-equal(_test-output-stream, "fe ff ", msg)
    # . . push args
    68/push  "F - test-emit-number-with-metadata"/imm32
    68/push  "fe ff "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-stream-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-emit-non-number:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # (eax..ecx) = "xyz"
    b8/copy-to-eax  "xyz"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var slice/ecx = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # emit(_test-output-buffered-file, slice, 2)
    # . . push args
    68/push  2/imm32
    51/push-ecx
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  emit/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-stream-equal(_test-output-stream, "xyz", msg)
    # . . push args
    68/push  "F - test-emit-non-number"/imm32
    68/push  "xyz "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-stream-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-emit-non-number-with-metadata:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # (eax..ecx) = "xyz/"
    b8/copy-to-eax  "xyz/"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var slice/ecx = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # emit(_test-output-buffered-file, slice, 2)
    # . . push args
    68/push  2/imm32
    51/push-ecx
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  emit/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-stream-equal(_test-output-stream, "xyz/", msg)
    # . . push args
    68/push  "F - test-emit-non-number-with-metadata"/imm32
    68/push  "xyz/ "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-stream-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-emit-non-number-with-all-hex-digits-and-metadata:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # (eax..ecx) = "abcd/xyz"
    b8/copy-to-eax  "abcd/xyz"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var slice/ecx = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # emit(_test-output-buffered-file, slice, 2)
    # . . push args
    68/push  2/imm32
    51/push-ecx
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  emit/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # dump output {{{
#?     # . write(2/stderr, "^")
#?     # . . push args
#?     68/push  "^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, _test-output-stream)
#?     # . . push args
#?     68/push  _test-output-stream/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # }}}
    # check-stream-equal(_test-output-stream, "abcd/xyz")
    # . . push args
    68/push  "F - test-emit-non-number-with-all-hex-digits"/imm32
    68/push  "abcd/xyz "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-stream-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

# conditions for 'valid' names that are not at risk of looking like hex numbers
# keep in sync with the rules in labels.cc
#: - if it starts with a digit, it's treated as a number. If it can't be
#:   parsed as hex it will raise an error.
#: - if it starts with '-' it's treated as a number.
#: - if it starts with '0x' it's treated as a number. (redundant)
#: - if it's two characters long, it can't be a name. Either it's a hex
#:   byte, or it raises an error.
is-valid-name?:  # in : (address slice) -> eax : boolean
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    51/push-ecx
    56/push-esi
    # esi = in
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
    # start/ecx = in->start
    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # copy *esi to ecx
    # end/eax = in->end
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy *(esi+4) to eax
$is-valid-name?:check0:
    # if (start >= end) return false
    39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # compare ecx with eax
    73/jump-if-greater-or-equal-unsigned  $is-valid-name?:false/disp8
$is-valid-name?:check1:
    # eax -= ecx
    29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
    # if (eax == 2) return false
    3d/compare-eax-and  2/imm32
    74/jump-if-equal  $is-valid-name?:false/disp8
$is-valid-name?:check2:
    # c/eax = *ecx
    31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
    8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
    # if (c == "-") return false
    3d/compare-eax-and  2d/imm32/-
    74/jump-if-equal  $is-valid-name?:false/disp8
$is-valid-name?:check3a:
    # if (c < "0") return true
    3d/compare-eax-with  30/imm32/0
    7c/jump-if-lesser  $is-valid-name?:true/disp8
$is-valid-name?:check3b:
    # if (c > "9") return true
    3d/compare-eax-with  39/imm32/9
    7f/jump-if-greater  $is-valid-name?:true/disp8
$is-valid-name?:false:
    # return false
    b8/copy-to-eax  0/imm32/false
    eb/jump  $is-valid-name?:end/disp8
$is-valid-name?:true:
    # return true
    b8/copy-to-eax  1/imm32/true
$is-valid-name?:end:
    # . restore registers
    5e/pop-to-esi
    59/pop-to-ecx
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-is-valid-name-digit-prefix:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # (eax..ecx) = "34"
    b8/copy-to-eax  "34"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var slice/ecx = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # eax = is-valid-name?(slice)
    # . . push args
    51/push-ecx
    # . . call
    e8/call  is-valid-name?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-is-valid-name-digit-prefix"/imm32
    68/push  0/imm32/false
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-is-valid-name-negative-prefix:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # (eax..ecx) = "-0x34"
    b8/copy-to-eax  "-0x34"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var slice/ecx = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # eax = is-valid-name?(slice)
    # . . push args
    51/push-ecx
    # . . call
    e8/call  is-valid-name?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-is-valid-name-negative-prefix"/imm32
    68/push  0/imm32/false
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-is-valid-name-0x-prefix:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # (eax..ecx) = "0x34"
    b8/copy-to-eax  "0x34"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var slice/ecx = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # eax = is-valid-name?(slice)
    # . . push args
    51/push-ecx
    # . . call
    e8/call  is-valid-name?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-is-valid-name-0x-prefix"/imm32
    68/push  0/imm32/false
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-is-valid-name-starts-with-pre-digit:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # (eax..ecx) = "/03"
    b8/copy-to-eax  "/03"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var slice/ecx = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # eax = is-valid-name?(slice)
    # . . push args
    51/push-ecx
    # . . call
    e8/call  is-valid-name?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 1, msg)
    # . . push args
    68/push  "F - test-is-valid-name-starts-with-pre-digit"/imm32
    68/push  1/imm32/true
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-is-valid-name-starts-with-post-digit:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # (eax..ecx) = "q34"
    b8/copy-to-eax  "q34"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var slice/ecx = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # eax = is-valid-name?(slice)
    # . . push args
    51/push-ecx
    # . . call
    e8/call  is-valid-name?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 1, msg)
    # . . push args
    68/push  "F - test-is-valid-name-starts-with-post-digit"/imm32
    68/push  1/imm32/true
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-is-valid-name-starts-with-digit:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # (eax..ecx) = "0x34"
    b8/copy-to-eax  "0x34"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var slice/ecx = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # eax = is-valid-name?(slice)
    # . . push args
    51/push-ecx
    # . . call
    e8/call  is-valid-name?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-is-valid-name-starts-with-digit"/imm32
    68/push  0/imm32/false
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

# print 'n' in hex in 'width' bytes in lower-endian order, with a space after every byte
emit-hex:  # out : (address buffered-file), n : int, width : int -> <void>
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    57/push-edi
    # edi = out
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
    # ebx = n
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           3/r32/ebx   0xc/disp8       .                 # copy *(ebp+12) to ebx
    # edx = width
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0x10/disp8      .                 # copy *(ebp+16) to edx
    # var curr/ecx = 0
    31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
$emit-hex:loop:
    # if (curr >= width) break
    39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
    7d/jump-if-greater-or-equal  $emit-hex:end/disp8
    # print-byte-buffered(out, ebx)
    # . . push args
    53/push-ebx
    57/push-edi
    # . . call
    e8/call  print-byte-buffered/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write-byte-buffered(out, ' ')
    # . . push args
    68/push  0x20/imm32/space
    57/push-edi
    # . . call
    e8/call  write-byte-buffered/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # ebx = ebx >> 8
    c1/shift    5/subop/logic-right 3/mod/direct    3/rm32/ebx    .           .             .           .           .               8/imm8            # shift ebx right by 8 bits, while padding zeroes
$emit-hex:continue:
    # ++curr
    41/increment-ecx
    eb/jump  $emit-hex:loop/disp8
$emit-hex:end:
    # . restore registers
    5f/pop-to-edi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-emit-hex-single-byte:
    # setup
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # emit-hex(_test-output-buffered-file, 0xab, 1)
    # . . push args
    68/push  1/imm32
    68/push  0xab/imm32
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  emit-hex/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(*_test-output-stream->data, 'ab ', msg)
    # . . push args
    68/push  "F - test-emit-hex-single-byte"/imm32
    68/push  0x206261/imm32
    # . . push *_test-output-stream->data
    b8/copy-to-eax  _test-output-stream/imm32
    ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           0xc/disp8       .                 # push *(eax+12)
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . end
    c3/return

test-emit-hex-multiple-byte:
    # setup
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # emit-hex(_test-output-buffered-file, 0x1234, 2)
    # . . push args
    68/push  2/imm32
    68/push  0x1234/imm32
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  emit-hex/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-stream-equal(_test-output-stream, "34 12 ", msg)
    # . . push args
    68/push  "F - test-emit-hex-multiple-byte/1"/imm32
    68/push  "34 12 "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-stream-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . end
    c3/return

test-emit-hex-zero-pad:
    # setup
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # emit-hex(_test-output-buffered-file, 0xab, 2)
    # . . push args
    68/push  2/imm32
    68/push  0xab/imm32
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  emit-hex/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check(_test-output-stream->data == 'ab 00 ')
    # . . push args
    68/push  "F - test-emit-hex-zero-pad/1"/imm32
    68/push  "ab 00 "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-stream-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . end
    c3/return

test-emit-hex-negative:
    # setup
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # emit-hex(_test-output-buffered-file, -1, 2)
    # . . push args
    68/push  2/imm32
    68/push  -1/imm32
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  emit-hex/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-stream-equal(_test-output-stream == "ff ff ")
    # . . push args
    68/push  "F - test-emit-hex-negative/1"/imm32
    68/push  "ff ff "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-stream-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . end
    c3/return

# print 'arr' in hex with a space after every byte
emit-hex-array:  # out : (address buffered-file), arr : (address array byte) -> <void>
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    57/push-edi
    # edi = out
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   8/disp8         .                 # copy *(ebp+8) to edi
    # edx = arr  # <== 0xbdffffe4
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
    # curr/ecx = arr->data
    8d/copy-address                 1/mod/*+disp8   2/rm32/edx    .           .             .           1/r32/ecx   4/disp8         .                 # copy edx+4 to ecx
    # max/edx = arr->data + arr->length
    8b/copy                         0/mod/indirect  2/rm32/edx    .           .             .           2/r32/edx   .               .                 # copy *edx to edx
    01/add                          3/mod/direct    2/rm32/edx    .           .             .           1/r32/ecx   .               .                 # add ecx to edx
    # eax = 0
    31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
$emit-hex-array:loop:
    # if (curr >= width) break
    39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
    73/jump-if-greater-or-equal-unsigned  $emit-hex-array:end/disp8
    # emit-hex(out, *curr, width=1)
    # . . push args
    68/push  1/imm32/width
    8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
    50/push-eax
    57/push-edi
    # . . call
    e8/call  emit-hex/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # ++curr
    41/increment-ecx
    eb/jump  $emit-hex-array:loop/disp8
$emit-hex-array:end:
    # . restore registers
    5f/pop-to-edi
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-emit-hex-array:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # setup
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # . clear-stream(_test-output-buffered-file+4)
    # . . push args
    b8/copy-to-eax  _test-output-buffered-file/imm32
    05/add-to-eax  4/imm32
    50/push-eax
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # var arr/ecx (address array byte) = [01, 02, 03]
    68/push  0x00030201/imm32  # bytes 01 02 03
    68/push  3/imm32/length
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # emit-hex-array(_test-output-buffered-file, arr)
    # . . push args
    51/push-ecx
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  emit-hex-array/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . flush(_test-output-buffered-file)
    # . . push args
    68/push  _test-output-buffered-file/imm32
    # . . call
    e8/call  flush/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # dump output {{{
#?     # . write(2/stderr, "result: ^")
#?     # . . push args
#?     68/push  "result: ^"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write-stream(2/stderr, _test-output-stream)
#?     # . . push args
#?     68/push  _test-output-stream/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . write(2/stderr, "$\n")
#?     # . . push args
#?     68/push  "$\n"/imm32
#?     68/push  2/imm32/stderr
#?     # . . call
#?     e8/call  write/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
#?     # . rewind-stream(_test-output-stream)
#?     # . . push args
#?     68/push  _test-output-stream/imm32
#?     # . . call
#?     e8/call  rewind-stream/disp32
#?     # . . discard args
#?     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
#?     # }}}
    # check-next-stream-line-equal(_test-output-stream, "01 02 03 ", msg)
    # . . push args
    68/push  "F - test-emit-hex-array"/imm32
    68/push  "01 02 03 "/imm32
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  check-next-stream-line-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

compute-width: # word : (address array byte) -> eax : int
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    51/push-ecx
    # eax = word
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to ecx
    # ecx = word + word->length
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    # eax = word->data
    05/add-to-eax  4/imm32
    # var in/ecx : (address slice) = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # return compute-width-of-slice(ecx)
    # . . push args
    51/push-ecx
    # . . call
    e8/call  compute-width-of-slice/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
$compute-width:end:
    # . reclaim locals
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . restore registers
    59/pop-to-ecx
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

compute-width-of-slice: # s : (address slice) -> eax : int
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    51/push-ecx
    # ecx = s
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
    # if (has-metadata?(word, "imm32")) return 4
    # . eax = has-metadata?(word, "imm32")
    # . . push args
    68/push  "imm32"/imm32
    51/push-ecx
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax != 0) return 4
    3d/compare-eax-and  0/imm32
    b8/copy-to-eax  4/imm32         # ZF is set, so we can overwrite eax now
    75/jump-if-not-equal  $compute-width-of-slice:end/disp8
    # if (has-metadata?(word, "disp32")) return 4
    # . eax = has-metadata?(word, "disp32")
    # . . push args
    68/push  "disp32"/imm32
    51/push-ecx
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax != 0) return 4
    3d/compare-eax-and  0/imm32
    b8/copy-to-eax  4/imm32         # ZF is set, so we can overwrite eax now
    75/jump-if-not-equal  $compute-width-of-slice:end/disp8
    # if (has-metadata?(word, "imm16")) return 2
    # . eax = has-metadata?(word, "imm16")
    # . . push args
    68/push  "imm16"/imm32
    51/push-ecx
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax != 0) return 2
    3d/compare-eax-and  0/imm32
    b8/copy-to-eax  2/imm32         # ZF is set, so we can overwrite eax now
    75/jump-if-not-equal  $compute-width-of-slice:end/disp8
    # if (has-metadata?(word, "disp16")) return 2
    # . eax = has-metadata?(word, "disp16")
    # . . push args
    68/push  "disp16"/imm32
    51/push-ecx
    # . . call
    e8/call  has-metadata?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # . if (eax != 0) return 2
    3d/compare-eax-and  0/imm32
    b8/copy-to-eax  2/imm32         # ZF is set, so we can overwrite eax now
    75/jump-if-not-equal  $compute-width-of-slice:end/disp8
    # otherwise return 1
    b8/copy-to-eax  1/imm32
$compute-width-of-slice:end:
    # . restore registers
    59/pop-to-ecx
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-compute-width:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
$test-compute-width:imm8:
    # eax = compute-width("0x2/imm8")
    # . . push args
    68/push  "0x2/imm8"/imm32
    # . . call
    e8/call  compute-width/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 1, msg)
    # . . push args
    68/push  "F - test-compute-width: 0x2/imm8"/imm32
    50/push-eax
    68/push  1/imm32
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
$test-compute-width:imm16:
    # eax = compute-width("4/imm16")
    # . . push args
    68/push  "4/imm16"/imm32
    # . . call
    e8/call  compute-width/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 2, msg)
    # . . push args
    68/push  "F - test-compute-width: 4/imm16"/imm32
    50/push-eax
    68/push  2/imm32
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
$test-compute-width:imm32:
    # eax = compute-width("4/imm32")
    # . . push args
    68/push  "4/imm32"/imm32
    # . . call
    e8/call  compute-width/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 4, msg)
    # . . push args
    68/push  "F - test-compute-width: 4/imm32"/imm32
    50/push-eax
    68/push  4/imm32
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
$test-compute-width:disp8:
    # eax = compute-width("foo/disp8")
    # . . push args
    68/push  "foo/disp8"/imm32
    # . . call
    e8/call  compute-width/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 1, msg)
    # . . push args
    68/push  "F - test-compute-width: foo/disp8"/imm32
    50/push-eax
    68/push  1/imm32
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
$test-compute-width:disp16:
    # eax = compute-width("foo/disp16")
    # . . push args
    68/push  "foo/disp16"/imm32
    # . . call
    e8/call  compute-width/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 2, msg)
    # . . push args
    68/push  "F - test-compute-width: foo/disp16"/imm32
    50/push-eax
    68/push  2/imm32
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
$test-compute-width:disp32:
    # eax = compute-width("foo/disp32")
    # . . push args
    68/push  "foo/disp32"/imm32
    # . . call
    e8/call  compute-width/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 4, msg)
    # . . push args
    68/push  "F - test-compute-width: foo/disp32"/imm32
    50/push-eax
    68/push  4/imm32
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
$test-compute-width:no-metadata:
    # eax = compute-width("45")
    # . . push args
    68/push  "45"/imm32
    # . . call
    e8/call  compute-width/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 1, msg)
    # . . push args
    68/push  "F - test-compute-width: 45 (no metadata)"/imm32
    50/push-eax
    68/push  1/imm32
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

is-label?: # word : (address slice) -> eax : boolean
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    51/push-ecx
    # ecx = word
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
    # ecx = word->end
    8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(ecx+4) to ecx
    # return *(word->end - 1) == ':'
    # . eax = 0
    31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
    # . eax = *((char *) word->end - 1)
    8a/copy-byte                    1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/AL    -1/disp8         .                 # copy byte at *(ecx-1) to AL
    # . return (eax == ':')
    3d/compare-eax-and  0x3a/imm32/colon
    b8/copy-to-eax  1/imm32/true
    74/jump-if-equal  $is-label?:end/disp8
    b8/copy-to-eax  0/imm32/false
$is-label?:end:
    # . restore registers
    59/pop-to-ecx
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-is-label?:
    # . prolog
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
$test-is-label?:true:
    # (eax..ecx) = "AAA:"
    b8/copy-to-eax  "AAA:"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var slice/ecx = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # is-label?(slice/ecx)
    # . . push args
    51/push-ecx
    # . . call
    e8/call  is-label?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 1, msg)
    # . . push args
    68/push  "F - test-is-label?:true"/imm32
    68/push  1/imm32
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
$test-is-label?:false:
    # (eax..ecx) = "AAA"
    b8/copy-to-eax  "AAA"/imm32
    8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/eax  1/index/ecx   .           1/r32/ecx   4/disp8         .                 # copy eax+ecx+4 to ecx
    05/add-to-eax  4/imm32
    # var slice/ecx = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
    # is-label?(slice/ecx)
    # . . push args
    51/push-ecx
    # . . call
    e8/call  is-label?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-is-label?:false"/imm32
    68/push  0/imm32
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilog
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

== data

_test-data-segment:
  64/d 61/a 74/t 61/a
_test-data-segment-end:

# . . vim:nowrap:textwidth=0