INITIALIZATION Knowledgebase: ki-dev-large Base Query: Please summarize the whole context. It is important that you include a summary for each file. All files should be included, so please make sure to go through the entire context Model: gemini-1.5-pro-preview-0409 Use Curl?: ================================================== **Elapsed Time: 0.00 seconds** ================================================== ROUTING Query type: summary ================================================== **Elapsed Time: 1.52 seconds** ================================================== PRIMER Primer: You are Simon, a highly intelligent personal assistant in a system called KIOS. You are a chatbot that can read knowledgebases through the "CONTEXT" that is included in the user's chat message. Your role is to act as an expert at summarization and analysis. In your responses to enterprise users, prioritize clarity, trustworthiness, and appropriate formality. Be honest by admitting when a topic falls outside your scope of knowledge, and suggest alternative avenues for obtaining information when necessary. Make effective use of chat history to avoid redundancy and enhance response relevance, continuously adapting to integrate all necessary details in your interactions. Use as much tokens as possible to provide a detailed response. ================================================== **Elapsed Time: 0.52 seconds** ================================================== FINAL QUERY Final Query: CONTEXT: ########## File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 1 Context: ```markdown # Web API Design ## Crafting Interfaces that Developers Love ### Author: Brian Mulloy --- ### Table of Contents 1. **Introduction** - Overview of Web APIs - Importance of Good Design 2. **Design Principles** - Consistency - Simplicity - Flexibility 3. **Best Practices** - Documentation - Versioning - Error Handling 4. **Tools and Frameworks** - Postman - Swagger - RAML 5. **Conclusion** - Summary of Key Points --- ### Links - [Postman](https://www.postman.com) - [Swagger](https://swagger.io) - [RAML](https://raml.org) --- ### Notes - Always aim for clarity and conciseness when designing APIs. - Engage with developers to understand their needs and challenges. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 2 Context: ```markdown # Table of Contents ## Web API Design - Crafting Interfaces that Developers Love 1. [Introduction](#introduction) ....................................................................... 3 2. [Nouns are good; verbs are bad](#nouns-are-good-verbs-are-bad) .......... 4 3. [Plural nouns and concrete names](#plural-nouns-and-concrete-names) ... 8 4. [Simplify associations - sweep complexity under the ‘?’](#simplify-associations) ........................... 9 5. [Handling errors](#handling-errors) ................................................................. 10 6. [Tips for versioning](#tips-for-versioning) ................................................... 13 7. [Pagination and partial response](#pagination-and-partial-response) .......... 16 8. [What about responses that don’t involve resources?](#what-about-responses) .......................... 19 9. [Supporting multiple formats](#supporting-multiple-formats) ........................ 20 10. [What about attribute names?](#what-about-attribute-names) ...................... 21 11. [Tips for search](#tips-for-search) ............................................................... 22 12. [Consolidate API requests in one subdomain](#consolidate-api-requests) ... 23 13. [Tips for handling exceptional behavior](#tips-for-handling-exceptional-behavior) .... 25 14. [Authentication](#authentication) ............................................................ 27 15. [Making requests on your API](#making-requests-on-your-api) .................. 28 16. [Chatty APIs](#chatty-apis) ............................................................. 30 17. [Complement with an SDK](#complement-with-an-sdk) ............................. 31 18. [The API Façade Pattern](#the-api-facade-pattern) .................................... 32 ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 6 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love Think about the method calls required to address all the objects in the dogs' world. The URLs for our resource might end up looking something like this: | URL | URL | |------------------------------------|------------------------------------| | `/getAllDogs` | `/getAllLeashedDogs` | | `/verifyLocation` | `/verifyVeterinarianLocation` | | `/feedNeeded` | `/feedNeededFood` | | `/createRecuringWakeUp` | `/createRecurringMedication` | | `/giveDirectOrder` | `/doClientOwnerDiscipline` | | `/checkHealth` | `/dobExpressCheckupWithVeterinarian` | | `/getRecuringWakeUpSchedule` | `/getRecuringFeedingSchedule` | | `/getLocation` | `/getHungerLevel` | | `/getDog` | `/getSquirrelsChasingPuppies` | | `/newDog` | `/newDogForOwner` | | `/getNewDogsSince` | `/getNewDogsAtKennelSince` | | `/getRedDogs` | `/getRedDogsWithoutSiblings` | | `/getSittingDogs` | `/getSittingDogsAtPark` | | `/setDogsStateTo` | `/setLeashedDogsStateTo` | | `/replaceSittingDogsWithRunningDogs` | `/replaceParkSittingDogsWithRunningDogs` | | `/saveDog` | `/saveMommaDogsPuppies` | It's a slippery slope - soon you have a long list of URLs and no consistent pattern making it difficult for developers to learn how to use your API. ## Use HTTP verbs to operate on the collections and elements. For our dog resources, we have two base URLs that use nouns as labels, and we can operate on them with HTTP verbs. Our HTTP verbs are `POST`, `GET`, `PUT`, and `DELETE`. (We think of them as mapping to the acronym, CRUD (Create-Read-Update-Delete).) With our two resources (`/dogs` and `/dogs/1234`) and the four HTTP verbs, we have a rich set of capability that’s intuitive to the developer. Here is a chart that shows what we mean for our dogs. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 7 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love | Resource | POST create | GET read | PUT update | DELETE delete | |-----------------|---------------------|----------------|-------------------------|-------------------| | /dogs | Create a new dog | List dogs | Bulk update dogs | Delete all dogs | | /dogs/1234 | Error | Show Bo | If exists update Bo | Delete Bo | | | | | If not error | | The point is that developers probably don't need the chart to understand how the API behaves. They can experiment with and learn the API without the documentation. In summary: - Use two base URLs per resource. - Keep verbs out of your base URLs. - Use HTTP verbs to operate on the collections and elements. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 9 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## Simplify associations - sweep complexity under the '?' In this section, we explore API design considerations when handling associations between resources and parameters like states and attributes. ### Associations Resources almost always have relationships to other resources. What's a simple way to express these relationships in a Web API? Let's look again at the API we modeled in nouns; nouns are good, verbs are bad - the API that interacts with our `dogs` resource. Remember, we had two base URLs: `/dogs` and `/dogs/1234`. We're using HTTP verbs to operate on the resources and collections. Our dogs belong to owners. To get all the dogs belonging to a specific owner, or to create a new dog for that owner, do a `GET` or a `POST`: ``` GET /owners/5678/dogs POST /owners/5678/dogs ``` Now, the relationships can be complex. Owners have relationships with veterinarians, who have relationships with dogs, who have relationships with food, and so on. It's not uncommon to see people string these together making a URL 5 or 6 levels deep. Remember that once you have the primary key for one level, you usually don't need to include the levels above because you've already got your specific object. In other words, you shouldn't need too many cases where a URL is deeper than what we have above: ``` /resource/identifier/resource ``` ### Sweep complexity behind the '?' Most APIs have intricacies beyond the base level of a resource. Complexities can include many states that can be updated, changed, queried, as well as the attributes associated with a resource. Make it simple for developers to use the base URL by putting optional states and attributes behind the HTTP question mark. To get all red dogs running in the park: ``` GET /dogs?color=red&state=running&location=park ``` In summary, keep your API intuitive by simplifying the associations between resources, and sweeping parameters and other complexities under the rug of the HTTP question mark. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 10 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## Handling Errors Many software developers, including myself, don't always like to think about exceptions and error handling, but it is a very important piece of the puzzle for any software developer, and especially for API designers. ### Why is good error design especially important for API designers? From the perspective of the developer consuming your Web API, everything at the other side of that interface is a black box. Errors therefore become a key tool providing context and visibility into how to use an API. First, developers learn to write code through errors. The "test-first" concepts of the extreme programming model and the more recent "test-driven development" models represent a body of best practices that have evolved because this is such an important and natural way for developers to work. Secondly, in addition to when they're developing their applications, developers depend on well-designed errors at the critical times when they are troubleshooting and resolving issues after the applications they've built using your API are in the hands of their users. ### How to think about errors in a pragmatic way with REST? Let's take a look at how three top APIs approach it. #### Facebook **HTTP Status Code:** 200 ```json { "type": "OauthException", "message": "(#803) Some of the aliases you requested do not exist: foo.bar" } ``` #### Twilio **HTTP Status Code:** 401 ```json { "status": "401", "message": "Authenticate", "code": 20003, "more_info": "http://www.twilio.com/docs/errors/20003" } ``` #### SimpleGeo **HTTP Status Code:** 401 ```json { "code": 401, "message": "Authentication Required" } ``` ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 11 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## Facebook No matter what happens on a Facebook request, you get back the 200-status code - everything is OK. Many error messages also push down into the HTTP response. Here they also throw an #803 error but with no information about what #803 is or how to react to it. ## Twilio Twilio does a great job aligning errors with HTTP status codes. Like Facebook, they provide a more granular error message but with a link that takes you to the documentation. Community commenting and discussion on the documentation helps to build a body of information and adds context for developers experiencing these errors. ## SimpleGeo SimpleGeo provides error codes but with no additional value in the payload. ## A couple of best practices ### Use HTTP status codes Use HTTP status codes and try to map them cleanly to relevant standard-based codes. There are over 70 HTTP status codes. However, most developers don't have all 70 memorized. So if you choose status codes that are not very common you will force application developers away from building their apps and over to Wikipedia to figure out what you're trying to tell them. Therefore, most API providers use a small subset. For example, the Google GData API uses only 10 status codes; Netflix uses 9, and Digg, only 8. ### Google GData ``` | Code | Explanation | |------|-------------| | 200 | OK | | 201 | Created | | 304 | Not Modified | | 400 | Bad Request | | 401 | Unauthorized| | 403 | Forbidden | | 404 | Not Found | | 409 | Conflict | | 410 | Gone | | 500 | Internal Server Error | ``` ### Netflix ``` | Code | Explanation | |------|-------------| | 200 | OK | | 201 | Created | | 304 | Not Modified | | 400 | Bad Request | | 401 | Unauthorized| | 403 | Forbidden | | 404 | Not Found | | 412 | Precondition Failed | | 500 | Internal Server Error | ``` ### Digg ``` | Code | Explanation | |------|-------------| | 200 | OK | | 400 | Bad Request | | 401 | Unauthorized| | 403 | Forbidden | | 404 | Not Found | | 410 | Gone | | 500 | Internal Server Error | | 503 | Service Unavailable | ``` ### How many status codes should you use for your API? When you boil it down, there are really only 3 outcomes in the interaction between an app and an API: - Everything worked - success - The application did something wrong - client error - The API did something wrong - server error ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 13 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## Tips for Versioning Versioning is one of the most important considerations when designing your Web API. ### Never release an API without a version and make the version mandatory. Let's see how three top API providers handle versioning. | Provider | Versioning Example | |------------------|--------------------------------------| | Twilio | `/2010-04-01/Accounts/` | | salesforce.com | `/services/data/v20.0/sobjects/Account` | | Facebook | `?v=1.0` | **Twilio uses a timestamp in the URL (note the European format).** At compilation time, the developer includes the timestamp of the application when the code was compiled. That timestamp goes in all the HTTP requests. When a request arrives, Twilio does a look-up. Based on the timestamp, they identify the API that was valid when this code was created and route accordingly. It's a very clever and interesting approach, although we think it is a bit complex. For example, it can be confusing to understand whether the timestamp is the compilation time or the timestamp when the API was released. **Salesforce.com uses v20.0, placed somewhere in the middle of the URL.** We like the use of the v. notation. However, we don't like using the .0 because it implies that the interface might be changing more frequently than it should. The logic behind an interface can change rapidly but the interface itself shouldn’t change frequently. **Facebook also uses the v. notation but makes the version an optional parameter.** This is problematic because as soon as Facebook forced the API up to the next version, all the apps that didn’t include the version number broke and had to be pulled back and version number added. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 14 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## How to think about version numbers in a pragmatic way with REST? - Never release an API without a version. Make the version mandatory. - Specify the version with a `v` prefix. Move it all the way to the left in the URL so that it has the highest scope (e.g. `/v1/dogs`). - Use a simple ordinal number. Don't use the dot notation like `v1.2` because it implies a granularity of versioning that doesn't work well with APIs—it's an interface not an implementation. Stick with `v1`, `v2`, and so on. ### How many versions should you maintain? Maintain at least one version back. ### For how long should you maintain a version? Give developers at least one cycle to react before obsoleting a version. Sometimes that's 6 months; sometimes it's 2 years. It depends on your developers' development platform, application type, and application users. For example, mobile apps take longer to rev than Web apps. ## Should version and format be in URLs or headers? There is a strong school of thought about putting format and version in the header. Sometimes people are forced to put the version in the header because they have multiple inter-dependent APIs. That is often a symptom of a bigger problem, namely, they are usually exposing their internal mess instead of creating one, usable API facade on top. That's not to say that putting the version in the header is a symptom of a problematic API design. It's not! In fact, using headers is more correct for many reasons: it leverages existing HTTP standards, it's intellectually consistent with Fielding's vision, it solves some hard real-world problems related to inter-dependent APIs, and more. However, we think the reason most of the popular APIs do not use it is because it's less fun to hack in a browser. ### Simple rules we follow: 1. If it changes the logic you write to handle the response, put it in the URL so you can see it easily. 2. If it doesn't change the logic for each response, like OAuth information, put it in the header. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 16 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## Pagination and Partial Response Partial response allows you to give developers just the information they need. Take for example a request for a tweet on the Twitter API. You’ll get much more than a typical Twitter app often needs— including the name of the person, the text of the tweet, a timestamp, how often the message was re-tweeted, and a lot of metadata. Let’s look at how several leading APIs handle giving developers just what they need in responses, including Google who pioneered the idea of **partial response**. ### LinkedIn ``` /people:(id,first-name,last-name,industry) ``` This request on a person returns the ID, first name, last name, and the industry. LinkedIn does partial selection using this terse `:(...)` syntax which isn’t self-evident. Plus, it’s difficult for a developer to reverse engineer the meaning using a search engine. ### Facebook ``` /joe.smith/friends?fields=id,name,picture ``` ### Google ``` ?fields=title,media:group(media:thumbnail) ``` Google and Facebook have a similar approach, which works well. They each have an optional parameter called `fields` after which you put the names of fields you want to be returned. As you see in this example, you can also put sub-objects in responses to pull in other information from additional resources. ## Add Optional Fields in a Comma-Delimited List The Google approach works extremely well. Here’s how to get just the information we need from our dogs API using this approach: ``` /dogs?fields=name,color,location ``` It’s simple to read; a developer can select just the information an app needs at a given time; it cuts down on bandwidth issues, which is important for mobile apps. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 17 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love The partial selection syntax can also be used to include associated resources, cutting down on the number of requests needed to get the required information. ## Make it easy for developers to paginate objects in a database It's almost always a bad idea to return every resource in a database. Let's look at how Facebook, Twitter, and LinkedIn handle pagination. Facebook uses `offset` and `limit`. Twitter uses `page` and `rpp` (records per page). LinkedIn uses `start` and `count`. Semantically, Facebook and LinkedIn do the same thing. That is, the LinkedIn `start` and `count` are used in the same way as the Facebook `offset` and `limit`. To get records 50 through 75 from each system, you would use: - **Facebook** - `offset 50` and `limit 25` - **Twitter** - `page 3` and `rpp 25` (records per page) - **LinkedIn** - `start 50` and `count 25` ## Use limit and offset We recommend `limit` and `offset`. It is more common, well understood in leading databases, and easy for developers. ``` /dogs?limit=25&offset=50 ``` ## Metadata We also suggest including metadata with each response that is paginated that indicates to the developer the total number of records available. ## What about defaults? My loose rule of thumb for default pagination is `limit=10` with `offset=0`. ``` (limit=10&offset=0) ``` The pagination defaults are, of course, dependent on your data size. If your resources are large, you probably want to limit it to fewer than 10; if resources are small, it can make sense to choose a larger limit. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 19 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## What about responses that don’t involve resources? API calls that send a response that's not a resource *per se* are not uncommon depending on the domain. We’ve seen it in financial services, Telco, and the automotive domain to some extent. Actions like the following are your clue that you might not be dealing with a "resource" response. - Calculate - Translate - Convert For example, you want to make a simple algorithmic calculation like how much tax someone should pay, or do a natural language translation (one language in request; another in response), or convert one currency to another. None involve resources returned from a database. ### In these cases: #### Use verbs, not nouns For example, an API to convert 100 euros to Chinese Yen: ``` /convert?from=EUR&to=CNY&amount=100 ``` Make it clear in your API documentation that these “non-resource” scenarios are different. Simply separate out a section of documentation that makes it clear that you use verbs in cases like this – where some action is taken to generate or calculate the response, rather than returning a resource directly. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 20 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## Supporting multiple formats We recommend that you support more than one format - that you push things out in one format and accept as many formats as necessary. You can usually automate the mapping from format to format. Here's what the syntax looks like for a few key APIs. ### Google Data ``` ?alt=json ``` ### Foursquare ``` /venue.json ``` ### Digg* ``` Accept: application/json ?type=json ``` *The type argument, if present, overrides the `Accept` header. Digg allows you to specify in two ways: in a pure RESTful way in the `Accept` header or in the type parameter in the URL. This can be confusing - at the very least you need to document what to do if there are conflicts. We recommend the Foursquare approach. To get the JSON format from a collection or specific element: ``` dogs.json /dogs/1234.json ``` Developers and even casual users of any file system are familiar to this dot notation. It also requires just one additional character (the period) to get the point across. ## What about default formats? In my opinion, JSON is winning out as the default format. JSON is the closest thing we have to universal language. Even if the back end is built in Ruby on Rails, PHP, Java, Python, etc., most projects probably touch JavaScript for the front-end. It also has the advantage of being terse - less verbose than XML. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 21 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## What about attribute names? In the previous section, we talked about formats - supporting multiple formats and working with JSON as the default. This time, let's talk about what happens when a response comes back. You have an object with data attributes on it. How should you name the attributes? Here are API responses from a few leading APIs: - **Twitter** ```json "created_at": "Thu Nov 03 05:19:38 +0000 2011" ``` - **Bing** ```json "DateTime": "2011-10-29T09:35:00Z" ``` - **Foursquare** ```json "createdAt": 1320296464 ``` They each use a different code convention. Although the Twitter approach is familiar to me as a Ruby on Rails developer, we think that Foursquare has the best approach. How does the API response get back in the code? You parse the response (JSON parser); what comes back populates the object. It looks like this: ```javascript var myObject = JSON.parse(response); ``` If you chose the Twitter or Bing approach, your code looks like this. It's not JavaScript convention and looks weird - it looks like the name of another object or class in the system, which is not correct. ```javascript timing = myObject.created_at; timing = myObject.DateTime; ``` ## Recommendations - Use JSON as default - Follow JavaScript conventions for naming attributes - Use medial capitalization (aka CamelCase) - Use uppercase or lowercase depending on the type of object ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 23 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## Consolidate API requests in one subdomain We’ve talked about things that come after the top-level domain. This time, let’s explore stuff on the other side of the URL. Here’s how Facebook, Foursquare, and Twitter handle this: Facebook provides two APIs. They started with `api.facebook.com`, then modified it to orient around the social graph `graph.facebook.com`. - `graph.facebook.com` - `api.facebook.com` Foursquare has one API. - `api.foursquare.com` Twitter has three APIs; two of them focused on search and streaming. - `stream.twitter.com` - `api.twitter.com` - `search.twitter.com` It’s easy to understand how Facebook and Twitter ended up with more than one API. It has a lot to do with timing and acquisition, and it’s easy to reconfigure a CNAME entry in your DNS to point requests to different clusters. But if we’re making design decisions about what’s in the best interest of the app developer, we recommend following Foursquare’s lead: ### Consolidate all API requests under one API subdomain. It’s cleaner, easier, and more intuitive for developers who want to build cool apps using your API. Facebook, Foursquare, and Twitter also all have dedicated developer portals. - `developers.facebook.com` - `developers.foursquare.com` - `dev.twitter.com` ## How to organize all of this? Your API gateway should be the top-level domain. For example, `api.teachdogrest.com`. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 24 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love In keeping with the spirit of REST, your developer portal should follow this pattern: `developers.yourtopleveldomain`. For example, `developers.teachdogrest.com` ## Do Web redirects Then optionally, if you can sense from requests coming in from the browser where the developer really needs to go, you can redirect. Say a developer types `api.teachdogrest.com` in the browser but there's no other information for the GET request, you can probably safely redirect to your developer portal and help get the developer where they really need to be. - `api` → developers (if from browser) - `dev` → developers - `developer` → developers ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 25 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## Tips for handling exceptional behavior So far, we've dealt with baseline, standard behaviors. Here we'll explore some of the exceptions that can happen - when clients of Web APIs can't handle all the things we've discussed. For example, sometimes clients intercept HTTP error codes, or support limited HTTP methods. What are ways to handle these situations and work within the limitations of a specific client? ### When a client intercepts HTTP error codes One common thing in some versions of Adobe Flash - if you send an HTTP response that is anything other than HTTP 200 OK, the Flash container intercepts that response and puts the error code in front of the end user of the app. Therefore, the app developer doesn't have an opportunity to intercept the error code. App developers need the API to support this in some way. Twitter does an excellent job of handling this. They have an optional parameter `suppress_response_codes`. If `suppress_response_codes` is set to true, the HTTP response is always 200. ``` /public_timelines.json?suppress_response_codes=true HTTP status code: 200 {"error":"Could not authenticate you."} ``` Notice that this parameter is a big verbose response code. (They could have used something like `src`, but they opted to be verbose.) This is important because when you look at the URL, you need to see that the response codes are being suppressed as it has huge implications about how apps are going to respond to it. ### Overall recommendations: 1. Use `suppress_response_codes = true` 2. The HTTP code is no longer just for the code The rules from our previous Handling Errors section change. In this context, the HTTP code is no longer just for the code - the program - it's now to be ignored. Client apps are never going to be checking the HTTP status code, as it is always the same. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 26 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## 3 - Push any response code that we would have put in the HTTP response down into the response message In my example below, the response code is 401. You can see it in the response message. Also include additional error codes and verbose information in that message. ### Always return OK ```plaintext /dogs?suppress_response_codes=true ``` ### Code for ignoring ```plaintext 200 - OK ``` ### Message for people & code ```json { "response_code": 401, "message": "Verbose, plain language description of the problem with hints about how to fix it.", "more_info": "http://dev.teachdogrest.com/errors/12345", "code": 12345 } ``` ## When a client supports limited HTTP methods It is common to see support for GET and POST and not PUT and DELETE. To maintain the integrity of the four HTTP methods, we suggest you use the following methodology commonly used by Ruby on Rails developers: ### Make the method an optional parameter in the URL Then the HTTP verb is always a GET but the developer can express rich HTTP verbs and still maintain a RESTful clean API. #### Create ```plaintext /dogs?method=post ``` #### Read ```plaintext /dogs ``` #### Update ```plaintext /dogs/1234?method=put&location=park ``` #### Delete ```plaintext /dogs/1234?method=delete ``` > **WARNING:** It can be dangerous to provide post or delete capabilities using a GET method because if the URL is in a Web page then a Web crawler like the Googlebot can create or destroy lots of content inadvertently. Be sure you understand the implications of supporting this approach for your applications' context. 26 ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 27 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## Authentication There are many schools of thought. My colleagues at Apigee and I don't always agree on how to handle authentication - but overall here's my take. Let's look at these three top services. See how each of these services handles things differently: ### PayPal - Permissions Service API ### Facebook - OAuth 2.0 ### Twitter - OAuth 1.0a Note that PayPal's proprietary three-legged permissions API was in place long before OAuth was conceived. ### What should you do? Use the latest and greatest OAuth - OAuth 2.0 (as of this writing). It means that Web or mobile apps that expose APIs don’t have to share passwords. It allows the API provider to revoke tokens for an individual user, for an entire app, without requiring the user to change their original password. This is critical if a mobile device is compromised or if a rogue app is discovered. Above all, OAuth 2.0 will mean improved security and better end-user and consumer experiences with Web and mobile apps. Don't do something *like* OAuth, but different. It will be frustrating for app developers if they can’t use an OAuth library in their language because of your variation. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 29 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## Tell me about a particular dog **GET /dogs/1234** **Response** 200 OK ```json { "dog": { "id": "1234", "name": "Rover", "furColor": "brown" } } ``` ## Tell me about all the dogs **GET /dogs** **Response** 200 OK ```json { "dogs": [ { "dog": { "id": "1233", "name": "Fido", "furColor": "white" } }, { "dog": { "id": "1234", "name": "Rover", "furColor": "brown" } } ], "_metadata": [ { "totalCount": 327, "limit": 25, "offset": 100 } ] } ``` ## Delete Rover :( **DELETE /dogs/1234** **Response** 200 OK ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 30 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## Chatty APIs Let’s think about how app developers use that API you’re designing and dealing with chatty APIs. ### Imagine how developers will use your API When designing your API and resources, try to imagine how developers will use it to say construct a user interface, an iPhone app, or many other apps. Some API designs become very chatty—meaning just to build a simple UI or app, you have dozens or hundreds of API calls back to the server. The API team can sometimes decide not to deal with creating a nice, resource-oriented RESTful API, and just fall back to a mode where they create the 3 or 4 Java-style getter and setter methods they know they need to power a particular user interface. We don’t recommend this. You can design a RESTful API and still mitigate the chattiness. ### Be complete and RESTful and provide shortcuts First design your API and its resources according to [pragmatic RESTful design principles](https://www.example.com) and then provide shortcuts. What kind of shortcut? Say you know that 80% of all your apps are going to need some sort of composite response, then build the kind of request that gives them what they need. Just don’t do the latter instead of the former. First design using good pragmatic RESTful principles! ### Take advantage of the partial response syntax The partial response syntax discussed in a previous section can help. To avoid creating one-off base URLs, you can use the partial response syntax to drill down to dependent and associated resources. In the case of our dogs API, the dogs have association with owners, who in turn have associations with veterinarians, and so on. Keep nesting the partial response syntax using dot notation to get back just the information you need. ``` /owners/5678?fields=name,dogs.name ``` ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 31 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## Complement with an SDK It’s a common question for API providers - do you need to complement your API with code libraries and software development kits (SDKs)? If your API follows good design practices, is self-consistent, standards-based, and well documented, developers may be able to get rolling without a client SDK. Well-documented code samples are also a critical resource. On the other hand, what about the scenario in which building a UI requires a lot of domain knowledge? This can be a challenging problem for developers even when building UI and apps on top of APIs with pretty simple domains - think about the Twitter API with its primary object of 140 characters of text. You shouldn't change your API to try to overcome the domain knowledge hurdle. Instead, you can complement your API with code libraries and a software development kit (SDK). In this way, you don’t overburden your API design. Often, a lot of what’s needed is on the client side and you can push that burden to an SDK. The SDK can provide the platform-specific code, which developers use in their apps to invoke API operations - meaning you keep your API clean. Other reasons you might consider complementing your API with an SDK include: - **Speed adoption on a specific platform.** (For example, Objective C SDK for iPhone.) Many experienced developers are just starting off with Objective C so an SDK might be helpful. - **Simplify integration effort required to work with your API.** If key use cases are complex or need to be complemented by standard on-client processing. - **An SDK can help reduce bad or inefficient code** that might slow down service for everyone. As a developer resource - good SDKs are a forcing function to create good source code examples and documentation. Yahoo! and Paypal are good examples: - Yahoo! [http://developer.yahoo.com/social/sdk/](http://developer.yahoo.com/social/sdk/) - Paypal [https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/library_download_sdks](https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/library_download_sdks) To market your API to a specific community - you upload the SDK to a samples or plug-in page on a platform’s existing developer community. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 32 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## The API Façade Pattern At this point, you may be asking: **What should we be thinking from an architectural perspective?** **How do we follow all these best practice guidelines, expose my internal services and systems in a way that’s useful to app developers, and still iterate and maintain my API?** Back-end systems of record are often too complex to expose directly to application developers. They are stable (have been hardened over time) and dependable (they are running key aspects of your business), but they are often based on legacy technologies and not always easy to expose to Web standards like HTTP. These systems can also have complex interdependencies and they change slowly meaning that they can’t move as quickly as the needs of mobile app developers and keep up with changing formats. In fact, the problem is not creating an API for just one big system but creating an API for an array of complementary systems that all need to be used to make an API valuable to a developer. | Big System | DB | Content Mgmt | SOAP | JDBC | RSS | |------------|----------|---------------|------|------|------| | | | | | | | It’s useful to talk through a few anti-patterns that we’ve seen. Let’s look at why we believe they don’t work well. ## The Build Up Approach In the build-up approach, a developer exposes the core objects of a big system and puts an XML parsing layer on top. ``` XML Expose Objects ``` ``` Big System ``` ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 34 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## The Copy Cat Approach We sometimes see this pattern when an organization is late to market – for example, when their close competitor has already delivered a solution. Again, this approach can get you to version 1 quickly and you may have a built-in adoption curve if the app developers who will use your API are already familiar with your competitor's API. ![Competitor's API Doc](#) | Format | Service | System | |--------|----------------|------------| | XML | Expose | Big System | | XML | Expose | DB | | XML | Expose RSS | Content Mgmt| However, you can end up with an undifferentiated product that is considered an inferior offering in the market of APIs. You might have missed exposing your own key value and differentiation by just copying someone else's API design. ## Solution – The API façade pattern The best solution starts with thinking about the fundamentals of product management. Your product (your API) needs to be credible, relevant, and differentiated. Your product manager is a key member of your API team. Once your product manager has decided what the big picture is like, it’s up to the architects. We recommend you implement an **API façade pattern**. This pattern gives you a buffer or virtual layer between the interface on top and the API implementation on the bottom. You essentially create a façade – a comprehensive view of what the API should be and, importantly, from the perspective of the app developer and end user of the apps they create. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 36 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ![Web API Design Icon](link-to-icon) ## Ideal Design ![Ideal Design Diagram](link-to-ideal-design-diagram) ## API Facade ![API Facade Diagram](link-to-api-facade-diagram) ## Mediate | Big System | DB | Content Mgmt | SOAP | JDBC | RSS | |------------|----|---------------|------|------|-----| Using the three-step approach, you've decomposed one big problem into three smaller problems. If you try to solve the one big problem, you’ll be starting in code and trying to build up from your business logic (systems of record) to a clean API interface. You would be exposing objects or tables or RSS feeds from each silo, mapping each to XML in the right format before exposing to the app. It is a machine-to-machine orientation focused around an app and is difficult to get this right. Taking the façade pattern approach helps shift the thinking from a silo approach in a number of important ways. First, you can get buy-in around each of the three separate steps and have people more clearly understand how you’re taking a pragmatic approach to the design. Secondly, the orientation shifts from the app to the app developer. The goal becomes to ensure that the app developer can use your API because the design is self-consistent and intuitive. Because of where it is in the architecture, the façade becomes an interesting gateway. You can now have the façade implement the handling of common patterns (for pagination, queries, ordering, sorting, etc.), authentication, authorization, versioning, and so on, uniformly across the API. *(This is a big topic and a full discussion is beyond the scope of this article.)* Other benefits for the API team include being more easily able to adapt to different use cases regardless of whether they are internal developer, partner, or open scenarios. The API team will be able to keep pace with the changing needs of developers, including the ever-changing protocols and languages. It is also easier to extend an API by building out more capability from your enterprise or plugging in additional existing systems. ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 37 Context: ```markdown # Web API Design - Crafting Interfaces that Developers Love ## Resources - Representational State Transfer (REST), Roy Thomas Fielding, 2000 - [RESTful API Design Webinar](https://example.com), 2nd edition, Brian Mulloy, 2011 - [Apigee API Tech & Best Practices Blog](https://example.com) - [API Craft](https://example.com) Google Group ## About Brian Mulloy **Brian Mulloy, Apigee** Brian has 15 years of experience ranging from enterprise software to founding a Web startup. He co-founded and was CEO of Swivel, a website for social data analysis. He was President and General Manager of Grand Central, a cloud-based offering for application infrastructure (before we called it the cloud). He was also Director of Product Marketing at BEA Systems. Brian holds a degree in Physics from the University of Michigan. Brian is a frequent contributor on the [Apigee API Tech & Best Practices Blog](https://example.com), the [Apigee YouTube channel](https://example.com), the [API Craft](https://example.com) Google Group, and [Webinars](https://example.com). ``` #################### File: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf Page: 38 Context: ```markdown # Apigee Apigee is the leading provider of API products and technology for enterprises and developers. Hundreds of enterprises like Comcast, GameSpy, TransUnion Interactive, Guardian Life, and Constant Contact, as well as thousands of developers, use Apigee's technology. Enterprises use Apigee for visibility, control, and scale of their API strategies. Developers use Apigee to learn, explore, and develop API-based applications. Learn more at [apigee.com](http://apigee.com). ## Accelerate your API Strategy ## Scale Control and Secure your Enterprise ## Developers – Consoles for the APIs you ❤️ ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 1 Context: ```markdown # 10. The Network ## 10.1 Introduction Workstations are typically, but not always, connected in a local environment by a network. There exist two basically different views of the architecture of such nets. The more demanding view is that all connected stations constitute a single, unified workspace (also called address-space), in which the individual processors operate. It implies the demand that the “thin” connections between processors are hidden from the users. At worst they might become apparent through slower data access rates between the machines. To hide the difference between access within a computer and access between computers is regarded primarily as a challenge to implementors. The second, more conservative view, assumes that individual workstations are, although connected, essentially autonomous units which exchange data infrequently. Therefore, access of data on partner stations is initiated by explicit transfer commands. Commands handling external access are not part of the basic system, but rather are implemented in modules that might be regarded as applications. In the Oberon System, we adhere to this second view, and in this chapter, we describe the module **Net**, which is an autonomous command module based on the network driver SCC. It can be activated on any station connected in a network, and all of them are treated as equals. Such a set of loosely coupled stations may well operate in networks with moderate transmission rates and therefore with low-cost hardware interfaces and twisted-pair wires. An obvious choice for the unit of transferred data is the file. The central theme of this chapter is therefore file transfer over a network. Some additional facilities offered by a dedicated server station will be the subject of Chapter 11. The commands to be presented here are a few only: `SendFiles`, `ReceiveFiles`, and `SendMsg`. As explained in Chapter 2, Oberon is a single-process system where every command monopolizes the processor until termination. When a command involves communication over a network, (at least) two processors are engaged in the action at the same time. The Oberon paradigm therefore appears to exclude such cooperation; but fortunately it does not, and the solution to the problem is quite simple. Every command is initiated by a user operating on a workstation. For the moment we will call it the master (of the command under consideration). The addressed station - obviously called the server - must be in a state where it recognizes the command in order to engage in its execution. Since the command - called a **request** - arrives in encoded form over the network, an Oberon task represented by a handler procedure must be inserted into the event polling loop of the system. Such a handler must have the general form: ``` IF event present THEN handle event END ``` The guard, in this case, must imply that a request was received from the network. We emphasize that the event is sensed by the server only after the command currently under execution, if any, has terminated. However, data arrive at the receiver immediately after they are sent by the master. Hence, any sizable delay is inherently inadmissible, and the Oberon metaphor once again appears to fail. It does not fail, however, because the unavoidable, genuine concurrency of sender and receiver action is handled within the driver module which places the data into a buffer. The driver is activated by an interrupt, and its receiver buffer effectively decodes the partners and removes the stringent timing constraints. All this remains completely hidden within the driver module. ## 10.2 The Protocol If more than a single agent participates in the execution of a command, a convention must be established and obeyed. It defines the set of requests, their encoding, and the sequence of data. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 3 Context: ```markdown The source address is inserted automatically into packet headers by the driver. It is obtained from a DIP switch set when a computer is installed and connected. But where should the destination address come from? From the start, we reject the solution of an address table in every workstation because of the potential inconsistencies. The concept of a centralized authority holding a name/address dictionary is equally unattractive, because of the updates required whenever a person uses a different computer. Also, we have started from the premise to keep all participants in the network equal. The most attractive solution lies in a decentralized name service. It is based on the broadcast facility, i.e., the possibility to send a packet to all connected stations, bypassing their address filters with a special destination address (-1). The broadcast is used for emitting a name request containing the desired partner's symbolic name. A station receiving the request returns a reply to the requester, if that name matches its own symbolic name. The requester then obtains the desired partner's address from the source address field of the received reply. The corresponding simple protocol is: ``` NameRequest = NRQ partnername [NRS]. ``` Here, the already mentioned timeout facility is indispensable. The following summarizes the protocol developed so far: ``` protocol = {request}. request = ReceiveFile | SendFile | SendMsg | NameRequest. ``` The overhead incurred by name requests may be reduced by using a local address dictionary. In practice, a single entry is satisfactory. A name request is then needed whenever the partner changes. ## 10.4 The implementation Module `Net` is an implementation of the facilities outlined above. The program starts with a number of auxiliary, local procedures. They are followed by procedure `Serve` which is to be installed as an Oberon task, and the commands `SendFile`, `ReceiveFiles`, and `SendMsg`, each of which has its counterpart within procedure `Serve`. At the end are the commands for starting and stopping the server facility. For a more detailed presentation we select procedure `ReceiveFiles`. It starts out by reading the first parameter which designates the partner station from the command line. Procedure `FindPartner` issues the name request, unless the partner's address has already been determined by a previous command. The global variable `partner` records a symbolic name (ID) whose address is stored in the destination field of the global variable `head0`, which is used as a header in every packet sent by procedure `SCC.SendPacket`. The variable `partner` may be regarded as a name cache with a single entry and with the purpose of reducing the number of issued name requests. If the partner has been identified, the next parameter is read from the command line. It is the name of the file to be transmitted. If the parameter has the form `name0.name`, the file stored on the server as `name0.name` is fetched and stored locally as `name`. Hence, `name0` serves as a prefix of the file name on the server station. Thereafter, the request parameters are concatenated in the local buffer variable `buf`. They are the user’s name and password followed by the file name (user name and password remain unsung by the server procedure defined here). The command package is dispatched by the call `Send(SEND, buf)`, where `buf` records the length of the command parameter string. Then the reply packet is awaited by calling `ReceiveHead`. If the received packet's type is DAT with sequence number 0, a new file is established. Procedure `ReadData` receives the data and stores them in the new file, obeying the protocol defined in Section 10.2. This process is repeated for each file specified in the list of file names in the command line. Procedure `ReceiveHead(T)` receives packets and discards them until one arrives from the partner from which it is expected. The procedure represents an input filter in addition to the one provided by the partner. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 4 Context: ```markdown The hardware discriminates based on the packets’ source address, whereas the hardware filter distinguishes on the basis of the destination address. If no packet arrives within the allotted time `T`, a type code `-1` is returned, signifying a timeout. ## Procedure `ReceiveData` `ReceiveData` checks the sequence numbers of incoming data packets (type 0 - 7). If an incorrect number is detected, an ACK packet with the previous sequence number is returned (type 16 - 23), requesting a retransmission. At most two retries are undertaken. This seems to suffice considering that the server does not accept any other requests while being engaged in the transmission of a file. The part corresponding to `ReceiveFiles` within procedure `Serve` is guarded by the condition `head.typ = SND`. Variable `head` is the recipient of headers whenever a packet is received by `ReceiveHead`. First, the request’s parameters are scanned. `Id` and `pw` are ignored. Then the requested file is opened. If it exists, the transmission is handled by `ReceiveData`'s counterpart, procedure `SendData`. The time limit for receiving the next data packet is `T1`, whereas the limit of data waiting for retransmission is `T0`. `T1` is roughly `70` multiplied by the maximum number of possible (re)transmissions. Before disengaging itself from a transaction, the sender sends data waits until no further retransmission requests can be expected to arrive. The value `T0 (300)` corresponds to `1s`; the time for transmission of a packet of maximum length is about `16ms`. ## Procedure `SendFiles` Procedure `SendFiles` is designed analogously; its counterpart in the server is guarded by the condition `head.t typ = REC`. The server accepts the request only if its state is unprotected (global variable `protected`). Otherwise, the request is negatively acknowledged with an NPR packet. We draw attention to the fact that procedures `SendData` and `ReceiveData` are both used by command procedures as well as by the server. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 5 Context: ```markdown # 11. A Dedicated file-distribution and mail-server ## 11.1 Concept and structure In a system of loosely coupled workstations, it is desirable to centralize certain services. A first example is a common file store. Even if every station is equipped with a disk for permanent data storage, a common file service is beneficial, e.g., for storing the most recent versions of system files, reference documents, reports, etc. A common repository avoids inconsistencies which are inevitable when local copies are created. We call this a **file distribution service**. A centralized service is also desirable if it requires equipment whose cost and service would not warrant its acquisition for every workstation, particularly if the service is infrequently used. A prime example of this case is a **printing service**. The third case is a communication facility in the form of **electronic mail**. The repository of messages must inherently be centralized. We imagine it to have the form of a set of mailboxes, one for each user in the system. A mailbox needs to be accessible at all times, i.e., also when its owner's workstation has been switched off. A last example of a centralized service is a **time server**. It allows a station's real time clock to be synchronized with a central clock. In passing, we point out that every user has full control over his station, including the right to switch it on and off at any time. In contrast, the central server is continuously operational. In this chapter, we present a set of server modules providing all above mentioned services. They rest on the basic Oberon System without module **Net** (see Chapter 10). In contrast to **Net**, module **NetServer**, which handles all network communication, contains no command procedures (apart from those for starting and stopping it). This is because it never acts as a master. The counterparts of its server routines reside in other modules, including (an extended version of) **Net**, on the individual workstations. Routines for the file distribution service are the same as those contained in module **Net**, with the addition of permission checks based on the received user names and passwords. Routines for printing and mail service could in principle also be included in **NetServer** in the same way. But considerations of reliability and timing made this simple solution appear unsatisfactory. A weaker coupling in line of data transmission and data consumption is indeed highly desirable. Therefore, files received for printing or for dispatching into mailboxes are stored (by **NetServer**) into temporary files and thereafter "handed over" to the appropriate agent, i.e., the print server or the mail server. This data-centered interface between servers—in contrast to procedural interfaces—has the advantage that the individual servers are independent in the sense that none imports any other. Therefore, their development could proceed autonomously. Their connection is instead a module which defines a data structure and associated operators for passing temporary files from one server to another. The data structure used for this purpose is the first-in-first-out queue. We call it element tasks, because each one carries an objective and an object, the file to be processed. The module containing the FIFOs is called **Core**. The resulting structure of the involved modules is shown in Fig. 11.1. ![Figure 11.1](#) includes another server, **LineServer**, and shows the ease with which additional servers may be inserted into this scheme. They act as further sources and/or sinks for tasks, feeding or consuming the queues contained in **Core**. **LineServer** indeed produces and consumes tasks like **NetServer**. Instead of the RS-485 bus, it handles the RS-232 line which, connected to a modem, allows access to the server over telephone lines. We refrain from describing this module in further detail, because in many ways it is a mirror of **NetServer**. A centralized, open server calls for certain protection measures against unauthorized use. We recall that requests always carry a user identification and a password as parameters. The server ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 6 Context: ```markdown checks their validity by examining a table of users. The respective routines and the table are contained in module Core (see Sect. 11.5). ![Figure 11.1 Module structure of server systems](https://example.com/image-url) ## 11.2. Electronic Mail Service The heart of an e-mail service is the set of mailboxes stored on the dedicated central server. Each registered user owns a mailbox. The evidently necessary operations are the insertion of a message and its retrieval. In contrast to customary letter boxes, however, a retrieved message need not necessarily be removed from the box; its retrieval produces a copy. The box thereby automatically becomes a repository, and messages can be retrieved many times. This scheme calls for an additional command which removes a message from the box. Also, a command is needed for delivering a table of contents, in which presumably each message is represented by an indication of its sender and time of arrival. The mail scheme suggested above results in the following commands: - `Net.MailBox ServerName`. This command fetches a table of contents of the current user's mailbox from the specified server and displays it in a new viewer. The user's name and password must have been registered previously by the command `System.SetUser`. - `Net.SendMail ServerName`. The text in the marked viewer is sent to the specified server. In order to be accepted, the text must begin with at least one line beginning with "To:" and containing at least one recipient. - `Net.ReceiveMail`. This command is contained in the title bar (menu) of the viewer who issued the request for the table of contents. Prior to issuing the command, the message to be read must have been specified by selecting a line in the table of contents in this viewer. This mail system presented here is primarily intended to serve as an exchange for short messages which are typically sent, received, read, and discarded. Mailboxes are not intended to serve as long term archives for a large and ever-growing number of long pieces of text. This restrictiveness of purpose allows to choose a reasonably simple implementation and results in efficient, practically instantaneous access to messages when the server is idle. The Oberon mail server used at ETH also provides communication with external correspondents. It connects to an external mail server which is treated as a source and a sink for messages (almost) like other customers. Additionally, messages sent to that server need to be encoded into a standardized format, and those received need to be decoded accordingly. The parts of module `MailServer` for encoding and decoding are not described in this book. We merely clue the reader that its design and implementation took a multiple of the time spent on the last local message exchange, to which we confine this presentation. From the structures explained in Section 11.1, it follows that three agents are involved in the transfer of messages from the user into a mailbox. Therefore, additions to the server system distribute over three modules. New commands are added to module `Net` (see Section 10.4); these procedures will be listed below. Their counterparts reside in module `NetServer` on the dedicated server. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 7 Context: ```markdown ## Figure 11.2 Path of messages to and from mailbox ![Net](path_to_image) wire **NetServer** --- **mail queue** --- **MailServer** --- **mail box** Communication between the master station and the dedicated server runs over the network and therefore calls for an extension of its protocol (see Sect. 10.2). The additions directly correspond to the four commands given above. - **MailBox** = MDR username password (datastream | NAK | NPR). - **SendMail** = RML username password (ACK (datastream | NAK | NPR)). - **ReceiveMail** = SML username password msgon (datastream | NAK | NPR). - **DeleteMail** = DML username password msgon (ACK | NAK | NPR). The message number is taken from the selected line in the mailbox viewer. The data transmitted are taken as (unfortunate) texts. This is in contrast to file transfers, where they are taken as any sequence of bytes. The four command procedures listed below belong to module **Net**; they are listed together with the auxiliary procedures **SendText** and **ReceiveText** which closely correspond to **SendData** and **ReceiveData** (see Sect. 10.4). We now turn our attention to the command procedures' counterparts in module **NetServer** listed in this Section. In order to explain these routines, a description of their interface with the mail server and a definition of the structure of mailboxes must precede. We begin with the simplest case, the counterpart of **SendMail**. It is the part of procedure **NetServer.Serve** which is guarded by the condition of **m.PL**, indicating a request to receive mail. As in all other services, the parameters username and password are read and the admissibility of the request is checked. The check is performed by procedure **Core.UserNo** which yields a negative number if service is to be refused. In the alternative case, procedure **ReceiveData** obtains the message and stores it on a file, which is thereafter inserted into the mail queue as a task to be handled by the mail server at a later time. This may involve distribution of the message to several mailboxes. Module **Core** is listed in Sect. 11.5. As mentioned before, it serves as link between the various server modules, defining the data types of the linking queues and also of mailboxes. Task queues are represented as FIFO-lists. The descriptor of type **Queue** contains a pointer to the first list element used for retrieval, and a pointer to the last element used for insertion (see Fig. 11.3). These pointers are not exported; instead, the next task is obtained by calling procedure **Core.GetTask** and it is deleted by **Core.RemoveTask**. There exist two exported variables of type **Queue**: **MailQueue** consumed by **MailServer**, and **PrintQueue** consumed by **PrintServer** (see Sect. 11.3). In fact, we use a third queue: **LineQueue** consumed by **LineServer**. Elements of queues are of type **TaskDesc** which specifies the file representing the task to be consumed. Additionally, it specifies the user number and identification of the task's originator. The procedures are provided by module **Core** for handling task queues: ```pascal PROCEDURE InsertTask(VAR Q: Queue; F: Files; VAR id: ARRAY OF CHAR; un: INTEGER); PROCEDURE GetTask(VAR Q: Queue; VAR F: Files; VAR id: ARRAY OF CHAR; VAR un: INTEGER); PROCEDURE RemoveTask(VAR Q: Queue); ``` The server's counterparts of the remaining mail commands access mailboxes directly. The simplicity of the required actions - a result of a carefully chosen mailbox representation - and considerations of efficiency do not warrant a detour via task queue and mail server. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 8 Context: ```markdown # Structure of Task Queue ![Figure 11.3 Structure of task queue](link_to_image) Every mailbox is represented as a file. This solution has the tremendous advantage that no special administration has to be introduced to handle a reserved partition of disk store for mail purposes. A mailbox file is partitioned into three parts: the block reservation part, the directory part, and the message part. Each part is quickly locatable, because the first two have a fixed length (32 and 31*32 = 992 bytes). The message part is regarded as a sequence of blocks (of 256 bytes), and each message occupies an integral number of adjacent blocks. Corresponding to each block, the block reservation part contains a single bit indicating whether or not the block is occupied by a message. Since the block reservation part is 32 bytes long, the message part contains at most 256 blocks, i.e., 64K bytes. The block length was chosen after an analysis of messages which revealed that the average message is less than 500 bytes long. The directory part consists of an array of 31 elements of type `MailEntry`, a record with the following fields: - `pos` and `len` indicate the index of the message's first block and the message's number of bytes; - `time` and `date` indicate the message's time of insertion, and originator indicates the message's source. The entries are linked (field `next`) in chronological order of their arrival, and entry 0 serves as the list's header. It follows that a mailbox contains at most 30 messages. An example of a mailbox data is shown in Figure 11.4. ## MailEntry ``` RECORD pos: next: INTEGER; len: LONGINT; time, date: INTEGER; originator: ARRAY 20 OF CHAR END; ## MResTab ``` MailDir = ARRAY 31 OF MailEntry; We are now in a position to implement the handler for requests for message retrieval. It is guarded by the condition `pos := NIL`. After a valid check, the respective requestor's mailbox file is opened. The mailbox opened is related by the global variable `MF` which acts as a single entry cache. The associated user number is given by the global variable `mailno`. Since typically several requests involving the same mailbox follow, this measure avoids the repeated reopening of the same file. Thereafter, a rider is directly positioned at the respective directory entry for reading the message's length and position in the message part. The rider is repositioned accordingly, and transmission of the message is handled by procedure `SendMail`. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 9 Context: ```markdown # Block reservation part ``` ``` 1 100000101111101111111 ``` ## Directory part | pos | len | time | date | orig | next | |-----|-----|---------|---------|--------|------| | 0 | 0 | 9.2 | | | | | | | 10:72:12| | | | | | | 15:21:91| | | | | 8 | 15 | 1.0 | | | | | 197 | 11.50| | 23:41:8| 6.6:81 | | | 12 | 20 | 2 | | | | ### Message part ``` 0 2 8 15 ``` ![Figure 11.4 State of mailbox file](https://example.com/image-url) Requests for the mailbox directory are handled by the routine guarded by the condition `type = MDIR`. The directory part must be read and converted into text. This task is supported by various auxiliary procedures (Append) which concatenate supplied data in a buffer for latter transmission. We emphasize that this request does not require the reading of any other part of the file, and therefore is very swift. The last of the four mail service requests (DML) deletes a specified message. Removal from the directory requires a relinking of the entries. Unused entries are marked by their `len` field having value 0. Also, the blocks occupied by the message become free. The block reservation part must be updated accordingly. In passing, we note that the use of files for representing mailboxes, in combination with the file distribution services residing on the same server station, allows anyone to access (and inspect) any mailbox. Although we do not claim that this system provides secure protection against snooping, a minimal effort for protection was undertaken by a simple encoding of messages in mailbox files. This encoding is not shown in the program listings contained in this book. One operation remains to be explained in more detail: the processing of tasks inserted into the mail queue. It consists of the insertion of the message represented by the task's file into one or several mailboxes. It involves the interpretation of the message's header, i.e., lines containing addresses, and the construction of a new header containing the name of the originator and the date of insertion into the mailbox. These actions are performed by procedures in module `MailServer`. Its procedure `Serve` is installed as an Oberon Task, and it is guarded by the condition `Core.MailQueue.n > 0`, indicating that at least one message needs to be dispatched. The originator's name is obtained from `Core.GetUserName(uno)`, where `uno` is the user number obtained from the queue entry. The actual time is obtained from `Oberon.GetClock`. The form of the new header is shown by the following example: ``` From: GuntherK Date: 12.08.91 09:34:15 ``` The received message's header is then searched for recipients. Their names are listed in header lines starting with `To:` (or `Cc:`). After a name has been read, the corresponding user number is obtained by calling `Core.UserNum`. Then the message is inserted into the designated mailbox by procedure `Dispatch`. The search for recipients continues, until a line is encountered that does not begin with `To:` (or `Cc:`). A negative user number indicates that the given name is not registered. In ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 10 Context: ```markdown In this case, the message is returned to the sender, i.e., inserted into the mailbox of the sender. An exception is the recipient "all" which indicates a broadcast to all registered users. ### Procedure Dispatch First opens the mailbox file of the user specified by the recipient number. If a mailbox exists, its block reservation part (mbfil) and its directory part (mdir) are read. Otherwise, a new, empty box is created. Then follows the search for a free slot in the directory and, if found, the search for a sufficient number of free, adjacent blocks in the message part. The number of required blocks is given by the message length. If either no free slot exists, or there is no large enough free space for the message part, the message is returned to the sender (identified by sno). If also this attempt fails, the message is redirected to the postmaster (with user number 0). The postmaster is expected to inspect his mailbox sufficiently often so that no overflow occurs. If the postmaster's mailbox also overflows, the message is lost. Only if all conditions for a successful completion are satisfied, is insertion begun. It starts with the marking of blocks in the reservation table and with the insertion of the new directory information. Table and directory are then updated on the file. Thereafter, the message with the constructed new header is written into the message part. Perhaps it may seem to the reader that the addition of a separate module `Mail/Server`, together with a new Oberon Task and the machinery of the mail queue, is not warranted by the relative simplicity of the insertion operation, and that it could have been incorporated into module `Net/Server` just as well as message extraction. The picture changes, however, if handling of external mail is to be added, and if access to mailboxes via other channels, such as the RS-232 line, is to be provided. The presented solution is based on a modular structure that facilitates such extensions without change of existing parts. External mail routines inevitably have to cope with message formats imposed by standards. Format transformations, encoding before sending to an external server and decoding before dispatching become necessary. Indeed, these operations have inflated module `Mail/Server` in a surprising degree. And lastly, the queuing machinery supports the easy insertion of additional message sources and provides a welcome decoupling and relaxation of timing constraints, particularly in the case of low-speed transmission media such as telephone lines. ### 11.4. Miscellaneous Services There exist a few additional services that are quite desirable under the presence of a central facility, and at the same time easy to include. They are briefly described in this section. The set of commands of the file distribution service is augmented by `Net.DeleteFiles` and `Net.Directory`, allowing the remote deletion of files and inspection of the server's directory. The command procedures are listed below and must be regarded as part of module `Net` (Sect. 10.4). They communicate with their counterparts in module `Net/Server` (Sect. 11.2), according to the following protocol: - **DeleteFile** - `DEL username password filename` (ACK | NAK | NPR). - **Directory** - `FDIR username password prefix` (datastream | NAK | NPR). The directory request carries a prefix; it uses procedure `FileDir.Enumerate` to obtain all file names starting with the specified prefix. Thereby the search can be limited to the relevant section of the directory. Since requests to the server are always guarded by a password, a facility is necessary to set and change the password stored by the server. The respective command is `Net.SetPassword`, and its handler in the server is guarded by the condition `npw = NPW`. The corresponding protocol is: - **NewPassword** - `NPW username oldpassword` (ACK | NAK | NRP). Finally, procedure `Net.GetTime` allows the workstation's real time clock to be adjusted to that of the central server. The protocol is: ``` GetTime = TRQ TIM time date. ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 12 Context: ```markdown # Stored Passwords Our solution lies in storing an encoded password. The command `System.SetUser`, which asks for a user identification and a password, immediately encodes the password, and the original is stored nowhere. The encoding algorithm is such that it is difficult to construct a corresponding decoder. ## Mail Service The mail service requires a third attribute in addition to identification and encoded password: the user's name as it is used for addressing messages. Identification typically consists of the user's initials; for the name, we suggest the full last name of the user and disallow cryptic abbreviations. ## Printing Service The printing service makes an accounting facility desirable. A fourth field in each user table entry serves as a count for the number of printed pages. As a result, there are four fields: `id`, `name`, `password`, and `count`. The table is not exported, but only accessible via procedures. `Core` is a good example of a resource hiding module. The program is listed below, and a few additional comments follow here. ### Procedures `UserNo(id)` and `UserNum(name)` yield the table index of the identified user; it is called user number and is used as a short encoding for recipients and senders within the mail server. In other servers, the number is merely used to check a request's validity. ## User Information The user information must certainly survive any intermission of server operation, be it due to software, hardware, or power failure. This requires that a copy of the user information is held on backup store (disk). The simplest solution would be to use a file for this purpose. But this would indeed make protection too vulnerable: files can be accessed easily, and we have refrained from introducing a file protection facility. Instead, the backup of the user information is held on a few permanently reserved sections on the server machine, which are inaccessible to the file system. ## Procedures Apart from procedures and variables constituting the queuing mechanism for tasks, the procedures exported from module `Core` all belong to the administration, and they can be divided into two categories. The first category contains the procedures used by the three servers presented in this Chapter, and they are `UserNo`, `UserNum`, `IncPageCount`, `SetPassword`, `GetUserName` and `GetFileName`. The second category consists of the procedures `NoUsers` and `GetUser` for inspecting table entries, and `InsertUser`, `DeleteUser`, `ClearPassword`, `ClearCounts`, and `Init` for making changes to the table. ## Client Module The client of the latter category is a module `Users` which is needed by the human administrator of the server facility. The reader may at this point wonder why a more advanced concept of administration has not been chosen, which would allow the human administrator to operate the server remotely. A quick analysis of the consequences of this widely used approach reveals that a substantial amount of additions to our system would be required. The issue of security and protection would become inflated into dimensions that are hardly justified for our local system. The first consequence would be a differentiation among levels of protection. The administrator would become a so-called super user with extra privileges, such as changing the user table. And so the game of trying to break the protection measures starts to become an interesting challenge. We have resisted the temptation to introduce additional complexity. Instead, we assume that physical access to the server station is reserved to the administrator. Naturally, module `Users` and in particular the symbol file of `Core` do not belong to the public domain. In concluding, we may point out that the impossibility of activating users' programs on the server station significantly reduces the possibilities for inflicting damage from the exterior. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 13 Context: ```markdown # 12 The compiler ## 12.1 Introduction The compiler is the primary tool of the system builder. It therefore plays a prominent role in the Oberon System, although it is not part of the basic system. Instead, it constitutes a tool module - an application - with a single command: `Compile`. It translates program texts into machine code. Therefore, it is a program inherently machine-dependent; it acts as the interface between source language and target computer. In order to understand the process of compilation, the reader needs to be familiar with the source language Oberon defined in Appendix 1, and with the target computer RISC, defined in Appendix 2. The language is defined as an infinite set of sequences of symbols taken from the language's vocabulary. It is described by a set of equations called syntax. Each equation defines a syntactic construct, or more precisely, the set of sequences of symbols belonging to that construct. It specifies how that construct is composed of other syntactic constructs. The meaning of programs is defined in terms of semantic rules governing each such construct. Compilation of a program text proceeds by analyzing the text and thereby decomposing it recursively into its constructs according to the syntax. When a construct is identified, code is generated according to the semantic rule associated with the construct. The components of the identified construct supply parameters for the generated code. It follows that we distinguish between two kinds of actions: analyzing steps and code generating steps. In a rough approximation we may say that the former are source language dependent and target computer dependent, whereas the latter are source language independent and target computer dependent. Although reality is somewhat more complex, the modular structure of this compiler clearly reflects this division. The main module of the compiler is ORP (for Oberon to RISC Parser) It is primarily dedicated to syntactic analysis, parsing. Upon recognition of a syntactic construct, an appropriate procedure is called the code generator module ORG (for Oberon to RISC Generator). Apart from parsing, ORP checks for type consistency of operands, and it computes the attributes of objects identified in declarations. Whereas ORP mirrors the source language and is independent of a target computer, ORG reflects the target computer, but is independent of the source language. Oberon program texts are regarded as sequences of symbols rather than sequences of characters. Symbols themselves, however, are sequences of characters. We refrain from explaining the reasons for this distinction, but mention that apart from special characters and pairs such as `*`, `:=`, as well as identifiers, numbers, and strings are classified as symbols. Furthermore, certain capital letter sequences are symbols, such as `IF`, `END`, etc. Each time the syntax analyzer (parser) proceeds to read the next symbol, it does this by calling procedure `Geth`, which constitutes the so-called scanner residing in module ORS (for Oberon to RISC Scanner). It reads from the source text as many characters as are needed to recognize the next symbol. In passing we note that the scanner alone reflects the definition of symbols in terms of characters, whereas the parser is based on the notion of symbols only. The scanner implements the abstraction of symbols. The recognition of symbols within a character sequence is called *lexical analysis*. Ideally, the recognition of any syntactic construct, say `A`, consisting of subconstructs, say `B1`, `B2`, ..., `Bn`, leads to the generation of code that depends only on (1) the semantic rules associated with `A`, and (2) on attributes of `B1`, `B2`, ..., `Bn`. If this condition is satisfied, the construct is said to be context-free, and if all constructs of a language are context-free, then the language is context-free. Syntax and semantics of Oberon adhere to this rule, although with a significant exception. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 15 Context: ```markdown uses the straight-forward scheme of sequential allocation of consecutively declared variables. An address is a pair consisting of a base address (in a register) and an offset. Global variables are allocated in the module's data section and the respective base address register is SB (Static Base, see Chapter 6). Local variables are allocated in a procedure activation record on the stack; the respective base register is SP (Stack Pointer). Offsets are positive integers. The amount of storage needed for a variable (called its size) is determined by the variable's type. The sizes of basic types are prescribed by the target computer's data representation. The following holds for the RISC processor: | Type | No. of bytes | |---------------------------|--------------| | BYTE, CHAR, BOOLEAN | 1 | | INTEGER, REAL, SET, POINTER, PROCEDURE | 4 | The size of an array is the size of the element type multiplied by the number of elements. The size of a record is the sum of the sizes of its fields. A complication arises due to so-called alignment. By alignment is meant the adjustment of an address to a multiple of the variable's size. Alignment is performed for variable addresses as well as for record field offsets. The motivation for alignment is the avoidance of double memory references for variables being "distributed" over two adjacent words. Proper alignment enhances processing speed quite significantly. Variable allocation using alignment is shown by the example in Fig. 12.2. ``` VAR b0: BYTE; int0: INTEGER; b1: BYTE; int1: INTEGER; ``` ``` b0 int0 b1 int1 ``` **Figure 12.2.** Alignment of variables We note in passing that a reordering of the four variables lessens the number of unused bytes, as shown in Fig. 12.3. ``` VAR int0, int1: INTEGER; b0, b1: BYTE; ``` ``` int0 int1 b1 b0 ``` **Figure 12.3.** Improved order of variables Memory instructions compute the address as the sum of a register (base) and an offset constant. Local variables use the stack pointer SP (R14) as base, global variables the static base SB (R13). Every module has its own SB value, and therefore access to global (and imported) variables requires two instructions, one for fetching the base value, and one for loading or storing data. If the compiler can determine whether the correct base value has already been loaded into the SB register, the former instruction is omitted. The first 7 sample patterns contain global variables only, and their base SB is assumed to hold the appropriate value. Parameters of branch instructions denote jump distances from the instruction's own location (PC-relative). ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 17 Context: ```markdown # Pattern3: Indexed Variables References to elements of arrays make use of the possibility to add an index value to an offset. The index must be present in a register and multiplied by the size of the array elements. (For integers with size 4 this is done by a shift of 2 bits). Then this index is checked whether it lies within the bounds specified in the array's declaration. This is achieved by a comparison, actually a subtraction, and a subsequent branch instruction causing a trap, if the index is either negative or beyond the upper bound. If the reference is to an element of a multi-dimensional array (matrix), its address computation involves several multiplications and additions. The address of an element \( A[i_1, \ldots, i_k] \) of a k-dimensional array A with lengths \( n_{k_1}, \ldots, n_{k_k} \) is: \[ A(i) + \left( \ldots \left( \left( (i_k \mod n_{k_k}) \times n_{k_{k-1}} + i_{k-1} \right) \times n_{k_{k-2}} + \ldots + i_2 \right) \times n_1 + i_1 \right) \] **Note:** For index checks, `CMP` is written instead of `SUB` to mark that the subtraction is merely a comparison, that the result remains unused and only the condition flag registers hold the result. ## MODULE Pattern3: ``` VAR i, j, k: INTEGER; 0, 4, 8, 12 a: ARRAY 10 OF INTEGER; 16 x: ARRAY 10, 10 OF INTEGER; 56 y: ARRAY 10, 10 OF INTEGER; 456 BEGIN k := a[i]; LDR R0 S8 CMP R1 R0 10 BLHI R12 LSL R0 R0 2 ADD R0 R0 S8 LDR R0 R0 16 STR R0 S8 n := a[5]; LDR R0 S8 STR R0 S8 12 x[i][j] := 2; LDR R0 S8 CMP R1 R0 10 BLHI R12 MUL R0 R0 40 ADD R0 R0 S8 LDR R0 S8 4 CMP R2 R1 10 BLHI R12 LSL R1 R1 2 ADD R0 R0 R1 MOV R1 R0 2 STR R1 R0 56 LDR R0 S8 CMP R1 R0 10 BLHI R12 MUL R1 R0 400 ADD R0 R0 S8 4 CMP R2 R1 10 BLHI R12 y[i][j] := 3; LDR R1 S8 CMP R1 R0 10 BLHI R12 MUL R1 R1 40 ADD R0 R0 R1 LDR R1 S8 CMP R2 R1 10 ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 19 Context: ```markdown # MODULE Pattern5; VAR INTEGER: s; SET; 0, 4; BEGIN IF n = 0 THEN LDR R0 S8 ... CMP R0 R0 BNE 5 INC(n) LDR R0 S8 ... ADD R0 R0 1 STR R0 S0 END; IF (n >= 0) AND (n < 100) THEN LDR R0 S8 ... LDR R0 S0 (n) CMP R0 R0 BLT 6 LDR R0 S8 ... CMP R0 R0 100 BGE 3 DEC(n) LDR R0 S8 ... SUB R0 R0 1 STR R0 0 END; IF ODD(n) OR (n IN s) THEN LDR S8 R0 ... LDR R0 S8 (n) AND R0 R0 BNE 5 LDR R0 S8 4 (s) LDR R1 S8 0 ADD R1 R1 1 ROL R0 R1 BPL 2 STR R0 S8 0 n = -1000 MOV R0 R0 -1000 STR R0 S0 END; IF n < 0 THEN LDR R0 S8 ... LDR R0 S0 CMP R0 R0 BGE 3 s = {} MOV R0 R0 {} STR R0 S8 4 B 17 ELSE LDR R0 S8 ... LDR R0 S0 CMP R0 R0 10 BGE 3 s = {0} MOV R0 R1 STR R0 S8 4 B 18 END; IF n < 100 THEN LDR R0 S8 ... LDR R0 S0 CMP R0 R0 100 BGE 3 s = {1} MOV R0 R0 2 STR R0 S8 4 B 3 ELSE s = {2} MOV R0 R4 LDR S8 R0 ... STR R0 S8 4 END; END Pattern5. # Pattern 6: While and repeat statements. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 20 Context: ```markdown # Pattern 6: Module Structure ```plaintext MODULE Pattern6; VAR i: INTEGER; BEGIN i := 0; WHILE i < 10 DO LDR R8 0 LDR R8 0 CMP R0 10 BGE 4 LDR R8 0 ADD R0 R2 STR R8 0 END; REPEAT i := i - 1; LDRB R8 0 LDR R0 R8 0 SUB R0 1 STR R0 R8 0 UNTIL i = 0; CMP R0 0 BNE -7 END Pattern6. ``` # Pattern 7: For Statements ```plaintext MODULE Pattern7; VAR i, m, n: INTEGER; BEGIN FOR i := 0 TO n - 1 DO LDR R8 1 SUB R1 R1 CMP LNK R0 R1 BGT 7 STR R0 8 LSL R0 1 STR R8 4 END; LDR R8 0 ADD R0 R1 1 B -11 END Pattern7. ``` # Pattern 8: Proper Procedures ```plaintext MODULE Pattern8; PROCEDURE P(k: INTEGER; VAR y: INTEGER); VAR x: INTEGER; BEGIN SUB SP SP 16 // adjust SP STR LNK SP 0 // push ret addr STR R0 SP 4 // push x STR R1 SP 8 // push @y z := x; LDR R0 SP 4 STR R0 SP 12; // z y := z; LDR R0 SP 12; // y END Pattern8. ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 22 Context: ```markdown # Assembly Code Example ```assembly x[i+1] = n+5 ADD R0, R1, R0 LDR R0, R0, 0 STR R0, SP, 16 LDR R0, SP, 12 ; i ADD R0, R1, 1 LDR R1, SP, 8 ; x.len CMP R2, R1 BLI R12 LSL R0, R0, 2 LDR R1, SP, 4 ; x ADD R0, R1, R0 ADD R1, R1, 5 STR R1, R0, 0 LDR R1, SP, 16 ; n ADD R1, R1, 5 STR R1, R0, 0 ADD SP, SP, 20 B R15 BEGIN P(a); ADD R0, R8, 0 ; a MOV R1, R0, 12 END Pattern/10. ## Pattern 11: Sets This code pattern exhibits the construction of sets. If the specified elements are constants, the set value is computed by the compiler. Otherwise, sequences of move and shift instructions are used. Since shift instructions do not check whether the shift count is within sensible bounds, the results are unpredictable if elements outside the range 0 .. 31 are involved. ```assembly MODULE Pattern11; VAR S: SET; m, n: INTEGER; BEGIN S := (m); LDR R0, SB, 4 ; m MOV R1, R1 LSL R0, R1, R0 STR R0, SB, 0 S := (0 .. n); LDR R0, SB, 8 ; n MOV R1, R0, -2 LSL R0, R1 XOR R0, R0, 1 STR R0, SB, 1 S := (m .. 31); LDR R0, SB, 4 ; m LDR R1, SB, 4 MOV R1, 31 MOV R1, R1, 31 MOV R2, R0, -2 LSL R1, R2, 1 LSL R2, R2, 0 XOR R0, R0, R1 STR R0, SB, 0 S := (m .. n); LDR R0, SB, 4 ; m LDR R1, SB, 4 ; n MOV R1, R1, -2 LSL R1, R2, 0 XOR R0, R0, R1 STR R0, SB, 0 IF n IN (2, 3, 5, 7, 11, 13) THEN MOV R0, R0, 28 LDR R1, SB, 8 ADD R1, R1, 1 ASR R0, R0, R1 BPL 2 ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 23 Context: ```markdown m → 1 MOV R0 R0 1 STR R0 S4 m END END Pattern11. # Pattern 12: Imported variables and procedures When a procedure is imported from another module, its address is unavailable to the compiler. Instead, the procedure is identified by a number obtained from the imported module's symbol file. In place of the offset, the branch instruction holds (1) the number of the imported module, (2) the number of the imported procedure, and (3) a link in the list of BL instructions calling an external procedure. This list is traversed by the linking loader, that computes the actual offset (fixup, see Chapter 6). Imported variables are also referenced by a variable's number. In general, an access required two instructions. The first loads the static base register SB from a global table with the address of that module's data section. The module number of the imported variable serves as index. The second instruction loads the address of the variable, using the actual offset fixed up by the loader. In the following example, modules Pattern12a and Pattern12b both export a procedure and a variable. They are referenced from the importing module Pattern12c. ```pascal MODULE Pattern12a; VAR k : INTEGER; PROCEDURE P*; BEGIN k := 1 END P; END Pattern12a. MODULE Pattern12b; VAR x : REAL; PROCEDURE Q*; BEGIN x := -1 END Q; END Pattern12b. MODULE Pattern12c; IMPORT Pattern12a, Pattern12b; VAR i : INTEGER; y : REAL; BEGIN i := Pattern12a.k; y := Pattern12b.x; END Pattern12c. # Pattern 13: Record extensions with pointers Fields of a record type R1, which is declared as an extension of a type R0, are simply appended to the fields of R0, i.e., their offsets are greater than those of the fields of R0. When a record is statically declared, its type is known by the compiler. If the record is referenced via a pointer, however, this is not the case. A pointer bound to a base type R0 may well refer to a record of an extension R1 of R0. Type tests (and type guards) allow to test for the actual type. This requires that a type can be identified at the time of program execution. Because the language defines name equivalence instead of structural equivalence of types, a type may be identified by a number. We use the address of a unique type descriptor for this purpose. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 26 Context: ```markdown # Pattern 15: Array assignments and strings. MODULE Pattern15: VAR s0, s1: ARRAY 32 OF CHAR; PROCEDURE P(x: ARRAY OF CHAR); END P; BEGIN s0 := "ABCDEF"; ADD R0 SB 0 @s0 ADD R1 SB 64 @"ABCDEF" LDR R2 R1 0 ADD R1 R1 4 STR R2 R0 0 ADD R0 R0 4 ASR R2 R2 24 // test for 0X BNE = 6 s0 := s1; ADD R0 SB 0 @s0 ADD R1 SB 32 @s1 MOV R2 R0 8 len LDR R3 R1 0 ADD R1 R1 4 STR R3 R0 0 ADD R0 R0 4 SUB R2 R2 1 BNE = 6 P(s1): ADD R0 SB 32 @s1 MOV R1 R0 32 len BL -38 P P("012345"): ADD R0 SB 72 @"012345" MOV R1 R0 7 len (incl 0X) BL -42 P P("%"): ADD R0 SB 80 @"%" MOV R1 R0 2 len BL -46 P END Pattern15. # Pattern 16: Predeclared procedures. MODULE Pattern16: VAR m: INTEGER; a: REAL; // SET b: ARRAY 10 OF INTEGER; s: ARRAY 16 OF CHAR; BEGIN INC(m); LDR R1 R0 0 @m ADD R1 R1 1 STR R1 R0 0 DEC(m, 10): ADD R0 SB 84 @n LDR R1 R0 0 SUB R1 R1 10 STR R1 R0 0 INCU(m, 3): ADD R0 SB 12 @u LDR R1 R0 0 OR R1 R1 8 STR R1 R0 0 END Pattern16. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 28 Context: ```markdown ROR R0 R0 STR R0 $8 12 y b := ODD(n); LDR R0 $8 4 n AND R0 R0 1 BEC 2 MOV R0 R1 B 1 MOV R0 0 STR R0 $8 16 b n := ORD(ch); LDB R0 $8 17 ch STR R0 $8 4 n n := FLOOR(x); LDR R0 $8 4 x MOV R1 R0 480H FAD R0 R0 R1 STR R0 $8 n y := FLT(m); LDR R0 $8 0 m MOV R1 R0 480H FAD R0 R0 R1 float STR R0 $8 12 y n := LSL(m, 3); LDR R0 $8 0 m LSL R0 $8 4 n n := ASR(m, 8); LDR R0 $8 0 m ASR R0 $8 4 STR R0 $8 4 m := ROR(m, n); LDR R1 $8 4 LDR R0 R0 R1 ROR R0 R0 R1 STR R0 $8 0 END Pattern17. ## 12.3. Internal data structures and module interfaces ### 12.3.1. Data structures In Section 12.1 it was explained that declarations inherently constitute context-dependence of the translation process. Although parsing still proceeds on the basis of a context-free syntax and relies on contextual information only in a few isolated instances, information provided by declarations affects the generated code significantly. During the processing of declarations, their information is transferred into the "symbol table", a data structure of considerable complexity, from where it is retrieved for the generation of code. This dynamic data structure is defined in module ORB in terms of two record types called `Object` and `Struct`. These types pervade all other modules with the exception of the scanner. They are therefore explained before further details of the compiler are discussed (see module ORB below). For each declared identifier an instance of type `Object` is generated. The record holds the identifier and the properties associated with the identifier given in its declaration. Since `Object` is a statically typed language, every object has a type. It is represented in the record by its `typ` field, which is a pointer to a record of type `Struct`. Since many objects may be of the same type, it is appropriate to record the type's attributes only once and to refer to them via a pointer. The properties of type `Struct` will be discussed below. The kind of object which a table entry represents is indicated by the field class. Its values are denoted by declared integer constants: `Var` indicates that the entry describes a variable, `Con` a constant, `Fid` a record field, `Par` a VAR-parameter, and `Proc` a procedure. Different kinds of entries carry different attributes. A variable or a parameter carries an address, a constant has a value, a record field has an offset, and a procedure has an entry address, a list of parameters, and a result type. For each class the introduction of an extended record type would seem advisable. This was not done, however, for three reasons. First, the compiler was formulated in (a subset of) ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 29 Context: ```markdown Module-2 which does not feature type extension. Second, not making use of type extensions would make it simpler to translate the compiler into other languages for porting the language to other computers. And third, all extensions were known at the time the compiler was planned. Hence extensibility provided no argument for the introduction of a considerable variety of types. The simplest solution lies in using the multi-purpose fields and /or class-specific attributes. For example, val holds an address for variables, parameters, and procedures, an offset for record fields, and a value for constants. The definition of a type yields a record of type `Struct`, regardless of whether it occurs within a type declaration, in which case also a record of type `Object` (class = `Typ`) is generated, or in a variable declaration, in which case the type remains anonymous. All types are characterized by a form and a size. A type is either a basic type or a constructed type. In the latter case it refers to one or more other types. Constructed types are arrays, records, pointers, and procedural types. The attribute `form` refers to this classification. Its value is an integer. Just as different object classes are characterized by different attributes, different forms have different attributes. Again, the introduction of extensions of type `Struct` was avoided. Instead, some of the fields of type `Struct` remain unused in some cases, such as for basic types, and others are used for form-specific attributes. For example, the attribute `base` refers to the element type in the case of an array, to the result type in the case of a procedural type, to the type to which a pointer is bound, or to the base type of a (extended) record type. The attribute `disc` refers to the parameter list in the case of a procedural type, or to the list of fields in the case of a record type. As an example, consider the following declarations. The corresponding data structure is shown in Fig. 12.5. For details, the reader is referred to the program listing of module ORB and the respective explanations. ```pascal CONST N = 100; TYPE Ptr = POINTER TO Rec; Rec = RECORD n: INTEGER; p, q: Ptr END; VAR k: INTEGER; a: ARRAY [0..N-1] OF INTEGER; PROCEDURE P(x: INTEGER): INTEGER; ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 30 Context: ```markdown # Figure 12.5. Representation of declarations | Object | Type | |---------------|-------------------| | name | class | | val | type | | next | desc | | | | | Pointer | 4 | | Record | 12 | | nil | desc | | k Var | p Fid | q Fid | x Var | intType | |--------------|------------------|------------|-----------|---------| | 0 | 4 | 8 | 4 | 4 | | 4 | | | | | | 100 | | | | | | nil | | | | | | 1 | | | | | Only entries representing constructed types are generated during compilation. An entry for each basic type is established by the compiler's initialization. It consists of an Object holding the standard type's identifier and a Struct indicating its form, denoted by one of the values `Byte`, `Bool`, `Char`, `Int`, `Real`, or `Set`. The object records of the basic types are anchored in global pointer variables in module ORB (which actually should be regarded as constants). Not only are entries created upon initialization for basic types, but also for all standard procedures. Therefore, every compilation starts out with a symbol table reflecting all standard, pervasive identifiers and the objects they stand for. We now return to the subject of Objects. Whereas objects of basic classes (`Const`, `Var`, `Par`, `Fid`, `Typ`, `SProc`, `SFunc`, and `Mod`) directly reflect declared identifiers and constitute the context in which statements and expressions are compiled, compilations of expressions typically generate. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 31 Context: ```markdown anonymous entities of additional, non-basic modes. Such entities reflect selectors, factors, terms, etc., i.e., constituents of expressions and statements. As such, they are of a transitory nature and hence are not represented by records allocated on the heap. Instead, they are represented by record variables local to the processing procedures and are therefore allocated on the stack. Their type is called `Item` and is a slight variation of the type `Object`. Items are not referenced via pointers. Let us assume, for instance, that a term `x*y` is parsed. This implies that the operator and both factors have been parsed already. The factors `x` and `y` are represented by two variables of type `Item` of `Var` mode. The resulting term is again described by an item, and since the product is transitory, i.e., has significance only within the expression of which the term is a constituent, it is to be held in a temporary location, in a register. In order to express that an item is located in a register, a new, non-basic mode `Reg` is introduced. Effectively, all non-basic modes reflect the target computer's architecture, in particular its addressing modes. The more addressing modes a computer offers, the more item modes are needed to represent them. The additional item modes required by the RISC processor are. They are declared in module `ORG`: | Reg | direct register mode | |------|----------------------| | RegI | indirect register mode | | Cond | condition code mode | The use of the types `Object`, `Item`, and `Struct` for the various modes and forms, and the meaning of their attributes are explained in the following tables: ### Objects: | class | val | a | b | r | |-------|------|-----|-----|-----| | 0 | Undf | | | | | 1 | Const| val | | | | 2 | Var | adr | base| | | 3 | Par | adr | off | | | 4 | Fld | off | off | | | 5 | Typo | TAdr| TAdr| modno| | 6 | SProc| num | | | | 7 | SFunc| num | | | | 8 | Mod | | | | | 10 | Reg | | regno| | | 11 | RegI | off | regno| | | 12 | Cond | | Tjmp| Fjmp| condition code | ### Structures: | form | nopFar | len | dsc | base | |------|--------|-----|-----|------| | 7 | Pointer| | base type | | 10 | ProcTyp| nopFar | param | result type | | 12 | Array | nofEl | element type | | 13 | Record | ext | lev | desc adr | fields | extension type | Items have an attribute called `lev` which is part of the address of the item. Positive values denote the level of nesting of the procedure in which the item is declared; `lev = 0` implies a global object. Negative values indicate that the object is imported from the module with number `-lev`. The three types `Object`, `Item`, and `Struct` are defined in module `ORB`, which also contains procedures for accessing the symbol table. ## 12.3.2. Module interfaces ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 32 Context: ```markdown Before embarking on a presentation of the compiler's main module, the parser, an overview of its remaining modules is given in the form of their interfaces. The reader is invited to refer to them when studying the parser. The interface of the scanner module `ORS` is simple. It defines the numeric values of all symbols. But its chief constituent is procedure `Get`. Each call yields the next symbol from the source text, identified by an integer. Global variables represent attributes of the read symbol in certain cases. If a number was read, `val` or `val`/hold its numeric value. If an identifier or a string was read, `str` holds the ASCII values of the characters read. Procedure `Mark` serves to generate a diagnostic output indicating a brief diagnostic and the scanner's current position in the source text. This procedure is located in the scanner, because only the scanner has access to its current position. `Mark` is called from all other modules. ```pascal DEFINITION ORS = ("Scanner") IMPORT Texts, Oberon; TYPE Ident = ARRAY 32 OF CHAR; VAR sel: INTEGER; val: REAL; id: Ident; str: ARRAY 256 OF CHAR; errn: BOOLEAN; PROCEDURE Mark(msg: ARRAY OF CHAR); PROCEDURE Get(VAR sym: INTEGER); PROCEDURE Init(source: Texts.Text; pos: INTEGER); END ORS. ``` Module `ORB` defines the basic data structures representing declared objects and their types. It also contains procedures for accessing these structures. `NewObj` serves to insert a new identifier, and it returns a pointer to the allocated object. `ThisObj` returns the pointer to the object whose name equals the global scanner variable `ORS.id`. `ThisImport` and `ThisField` determine imported objects and record fields with names equal to `ORS.id`. Procedure `Import` serves to read the specified symbol file and to enter its identifier in the symbol table (`class = Mod`). Finally, `Export` generates the symbol file of the compiled module, containing descriptions of all objects and structures marked for export. ```pascal DEFINITION ORB = ("Base table handler") TYPE Object = POINTER TO ObjDesc; Type = POINTER TO TypeDesc; ObjDesc = RECORD class, len, expn: INTEGER; expd: BOOLEAN; next: Object; type: Type; name: ORS.Ident; val: INTEGER; END; TypeDesc = RECORD form: ref, mon: INTEGER; (* 'ref' is used for import/export only *) noplft: INTEGER; (* (for records: extension level) *) len: INTEGER; (* (for records: address of descriptor) *) desc: TypeObj; (* desc.[typ]: Object; *) base: Type; size: INTEGER; END; VAR TypeScope: Object; byteType, boolType, charType, intType, realType, setType, nilType, noType, strType: Type; ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 33 Context: ```markdown # PROCEDURE Init; # PROCEDURE Close; # PROCEDURE NewObj(VAR obj: Object; id: ORS.Ident; class: INTEGER); # PROCEDURE ThisObj(): Object; # PROCEDURE ThisMethod(mod: Object): Object; # PROCEDURE OpenScope; # PROCEDURE CloseScope; # PROCEDURE Import(VAR mod: modid: ORS.Ident); # PROCEDURE Export(VAR mod: ORS.Ident); # END ORG. VAR newSF: BOOLEAN; VAR key: INTEGER; Module ORG contains the procedures for code generation. The names of these procedures indicate the respective constructs for which code is to be produced. Note that an individual code generator procedure is provided for every standard, predefined procedure. This is necessary because they generate in-line code. ## DEFINITION ORG; CONST WordSize = 4; ### TYPE Item = RECORD mode: INTEGER; type_: ORB.Type; a, b: INTEGER; rdb: BOOLEAN; (* "read only" *) END; VAR x: INTEGER; ### PROCEDURE MakeConstItem(VAR x: Item; typ: ORB.Type; var: INTEGER); ### PROCEDURE MakeRealItem(VAR x: Item; val: REAL); ### PROCEDURE MakeStringItem(VAR x: Item; len: INTEGER); ### PROCEDURE MakeIntItem(VAR x: Item; len: INTEGER); ### PROCEDURE MakeCharItem(VAR x: Item; obj: Object; curlex: INTEGER); ### PROCEDURE Field(VAR x: Item; obj: Object); ### PROCEDURE Index(VAR x: Item); (* x := x[y] *) ### PROCEDURE Deref(VAR x: Item); ### PROCEDURE BuffT(VAR x: Item; typ: ORB.Type; vararg: BOOLEAN); ### PROCEDURE Not(VAR x: Item); (* x := ~x, Boolean operators *) ### PROCEDURE And1(VAR x: Item); (* x := x & x *) ### PROCEDURE And2(VAR x: Item); (* x := x & OR *) ### PROCEDURE Or1(VAR x: Item); (* x := x OR x *) ### PROCEDURE Or2(VAR x: Item); ### PROCEDURE Neg(VAR x: Item); (* x := -x, arithmetic operators *) ### PROCEDURE AddOp(VAR x: Item); (* x := x + y *) ### PROCEDURE SubOp(VAR x: Item); (* x := x - y *) ### PROCEDURE MulOp(VAR x: Item); (* x := x * y *) ### PROCEDURE DivOp(VAR x: Item); (* x := x / y *) ### PROCEDURE RealOp(VAR x: Item); (* x := x op y *) ### PROCEDURE Singleton(VAR x: Item); (* x := x, set operators *) ### PROCEDURE SetVAR(VAR x: Item); (* x := x *) ### PROCEDURE Set(VAR x: INTEGER; VAR y: Item); (* x := x + y *) ### PROCEDURE SetOp(VAR x: INTEGER; VAR y: Item); (* x := x op y *) ### PROCEDURE Intellation(op: INTEGER; VAR x: Item); (* x := x*y *) ### PROCEDURE SetRelation(op: INTEGER; VAR x: Item); (* x := x < x *) ### PROCEDURE RealRelation(op: INTEGER; VAR x: Item); (* x := x < x *) ### PROCEDURE StringItem(VAR x: Item); (* x := x * y *) ### PROCEDURE StrToChar(VAR x: Item); (* assignments *) ### PROCEDURE Store(VAR x: VAR.Item); (* x := y *) ### PROCEDURE StoreString(VAR x: Item); (* x := y *) ### PROCEDURE CopyString(VAR x: Item); (* from x to y *) ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 34 Context: ```markdown # PROCEDURE Definitions - **VarParam**(VAR x: item; ftpe: ORB.Type); (* parameters *) - **ValueParam**(VAR x: item); - **OpenArrayParam**(VAR x: item); - **StringParam**(VAR x: item); - **For**(VAR x, y: item; (* For Statement *)) - **For1**(VAR x, y: z: item; VAR l: LONGINT); - **For2**(VAR x, y: item); (* Branches, procedure calls, procedure prolog and epilog *) - **Here**(l: LONGINT); - **Flump**(VAR l: LONGINT); - **CJump**(VAR x: item); - **BJump**(l: LONGINT); - **CJump**(VAR x: item; l: LONGINT); - **Flup**(VAR x: item); - **Proc**(VAR x: item; VAR r: LONGINT); - **Call**(VAR x: item; l: LONGINT); - **Enter**(protocols: LONGINT; localSize: LONGINT; int: BOOLEAN); - **Return**(form: INTEGER; VAR x: item; size: LONGINT; int: BOOLEAN); (* In-line code procedures *) - **Increment**(updown: LONGINT; VAR x, y: item); - **Include**(index: LONGINT; VAR x, y: item); - **Assert**(VAR x: item); - **New**(VAR x: item); - **Pack**(VAR x: item); - **Length**(VAR x: item); - **Get**(VAR x: item); - **Put**(VAR x: item); - **Copy**(VAR x, y: z: item); - **DPFS**(VAR x: item); - **LDFSR**(VAR x: item); - **LDR**(VAR x: item); (* In-line code functions *) - **Abs**(VAR x: item); - **Dord**(VAR x: item); - **Floor**(VAR x: item); - **Float**(VAR x: item); - **Ord**(VAR x: item); - **Len**(VAR x: item); - **Shift**(VAR LONGINT; VAR x, y: item); - **ABC**(VAR x: item); - **SBC**(VAR x: item); - **UML**(VAR x, y: item); - **Bit**(VAR x: item); - **Register**(VAR x: item); - **RVar**(VAR x: item); - **Add**(VAR x: item); - **Condition**(VAR x: item); ## Other Procedures - **Open**(n: INTEGER); - **SetDataSize**(id: LONGINT); - **Header**(); - **Close**(VAR mod: ORS.Id; key, refont: LONGINT); END ORG. # 12. A Parser The main module ORP constitutes the parser. Its single command **Compile** - at the end of the program listing - identifies the source text according to the Oberon command conventions. It then calls procedure **Module** with the identified source text as a parameter. The command forms are: ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 35 Context: ```markdown # ORP ## Compiler - **ORP.Compile @**: The most recent selection identifies the beginning of the source text. - **ORP.Compile ^**: The most recent selection identifies the name of the source file. - **ORP.Compile f1 ... f0, f1, ...**: are the names of source files. File names and the characters `@` and `^` may be followed by an option specification `/s`. Option `/s` enables the compiler to overwrite an existing symbol file, thereby invalidating clients. The parser is designed according to the proven method of top-down, recursive descent parsing with a look-ahead of a single symbol. The last symbol read is represented by the global variable `sym`. Syntactic entities are mirrored by procedures of the same name. Their goal is to recognize the specified construct in the source text. The start symbol and corresponding procedure is `Module`. The principal parser procedures are shown in Fig. 12.6, which also exhibits their calling hierarchy. Loops in the diagram indicate recursion in the syntactic definition. ``` Module ├── Declarations │ ├── Type │ │ ├── RecType │ │ └── ArrayType │ └── ParamList ├── ProcDecl ├── StatSeq │ └── expression │ └── SimpleExp │ ├── term │ │ ├── factor │ │ └── element └── FPSeq └── FormalTyp ``` **Figure 12.6**: Parser procedure hierarchy. The rule of parsing strictly based on a single-symbol look-ahead and without reference to context is violated in three places. The prominent violation occurs in statements. If the first symbol of a statement is an identifier, the decision of whether an assignment or a procedure call is to be recognized is based on contextual information, namely the class of the identified object. The second violation occurs in `qualified` if the identifier `x` preceding a period denotes a module, it is recognized together with the subsequent identifier as a qualified identifier. Otherwise, `x` supposedly denotes a record variable. The third violation is made in procedure `selector`; if an identifier is followed by a left parenthesis, the decision of whether a procedure call or a type guard is to be recognized is again made on the basis of contextual information, namely the mode of the identified object. A fairly large part of the program is devoted to the discovery of errors. Not only should they be properly diagnosed, but a much more difficult requirement is that the parsing process should continue on the basis of a good guess about the structure that the text should most likely have. The parsing process must continue with some assumption and possibly after skipping a short piece of the identified object. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 37 Context: ```markdown The WITH statement had been eliminated from the language in its revision of 2007. Here it reappears in the form of a case statement, whose cases are not labelled by integers, but rather by types. What formerly was written as ```plaintext IF x IS T1 THEN WITH x: T1 DO ... x ... END ELSIF x IS T2 THEN WITH x: T2 DO ... x ... END ELSIF ... END ``` is now written more simply and more efficiently as ```plaintext CASE x OF T1: ... x ... | T2: ... x ... | ... END ``` where T1 and T2 are extensions of the type T0 of the case variable x. Compilation of this form of case statement merges the regional type guard of the form with statements with the type test of the former if statements. This case statement represents the only case where a symbol table entry - the type of x - is modified during compilation of statements. When the end of the with statement is reached, the change must be reverted. ### 12.5 The scanner The scanner module ORS embodies the lexicographic definitions of the language, i.e. the definition of abstract symbols in terms of characters. The scanner's substance is procedure `Get`, which scans the source text and, for each call, identifies the next symbol and yields the corresponding integer code. It is most important that this process be as efficient as possible. Procedure `Get` recognizes letters indicating the presence of an identifier (or reserved word), and digits signalling the presence of a number. Also, the scanner recognizes comments and skips them. The global variable `ch` stands for the last character read. A sequence of letters and digits may either denote an identifier or a key word. In order to determine this, a search is made in a table containing all key words for each would-be identifier. This table is sorted alphabetically and according to the length of reserved words. It is initialized when the compiler is loaded. The presence of a digit signals a number. Procedure `Number` first scans the subsequent digits (and letters) and stores them in a buffer. This is necessary, because hexadecimal numbers are denoted by the postfix letter H (rather than a prefix character). The postfix letter X specifies that the digits denote a character. There exists one case in the language Oberon, where a look-ahead of a single character does not suffice to identify the next symbol. When a sequence of digits is followed by a period, this period may either be the decimal point of a real number, or it may be the first element of a range symbol ( ... ). Fortunately, the problem can be solved locally as follows: If, after reading digits and a period, a second period is present, the number symbol is returned, and the look-ahead variable `ch` is assigned the special value `7FX`. A subsequent call of `Get` then delivers the range symbol. Otherwise the period after the digit sequence belongs to the (real) number. ### 12.6 Searching the symbol table, and handling symbol files #### 12.6.1 The structure of the symbol table The symbol table constitutes the context in which statements and expressions are parsed. Each procedure establishes a scope of visibility of local identifiers. The records registering identifiers belonging to a scope are linked as a linear list. They are of type `Object`. Each object has a type. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 38 Context: ```markdown Types are represented by records of type `Type`. These two types pervade the entire compiler, and they are defined as follows: ```pascal TYPE Object = POINTER TO ObjDesc; Type = POINTER TO TypeDesc; ObjDesc = RECORD class: INTEGER; exp, pro: BOOLEAN; (* exported / read-only *) next: Object; type: Type; name: ORS.ident; val: INTEGER; END; TypeDesc = RECORD form: ref, min: INTEGER; (* ref is only used for import/export *) nopAr: INTEGER; (* for procedures; extension level for records *) len: INTEGER; (* for arrays, len = 0 -> open array; for records: addr of descriptor *) desc: type; (* type of arrays, records, pointers *) base: Type; (* for Byte, Bool and Char *) size: INTEGER; (* in bytes; always multiple of 4, except for Byte, Bool and Char *) END; ``` Procedures for generating and searching the lists are contained in module `ORB`. If a new identifier is to be added, procedure `NewObj` first searches the list, and if the identifier is already present, a double definition is diagnosed. Otherwise, the new element is appended, thereby preserving the order given by the source text. Procedures, and therefore also scopes, may be nested. Each scope is represented by the list of its declared identifiers, and the list of the currently visible scopes are again connected as a list. Procedure `OpenScope` appends an element and procedure `CloseScope` removes it. The list of scopes is anchored in the global variable `topScope` and linked by the field `desc`. It is treated like a stack. It consists of elements of type `Object`, each one being the header (`class = Head`) of the list of declared entities. As an example, the procedure for searching an object (with name `ORS.id`) is shown here: ```pascal PROCEDURE ThisObj() : Object; VAR s: Object; BEGIN s := topScope; REPEAT x := s.next; WHILE (x # NIL) AND (x.name # ORS.id) DO x := x.next s := desc; UNTIL (x # NIL) OR (s = NIL); RETURN x; END ThisObj; ``` A snapshot of a symbol table for an example with nested scopes is shown in Fig. 12.6. It is taken when the following declarations are parsed and when the statement `s` is reached. ```pascal VAR x: INTEGER; PROCEDURE P1: INTEGER; BEGIN END P1; PROCEDURE Q1: INTEGER; PROCEDURE R1: INTEGER; BEGIN END R1; BEGIN END Q1; ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 39 Context: ```markdown # 12.6.2 Symbol files A search of an identifier proceeds first through the scope list, and for each header its list of object records is scanned. This mirrors the scope rule of the language and guarantees that if several entities carry the same identifier, the most local one is selected. The linear list of objects represents the simplest implementation by far. A tree structure would in many cases be more efficient for searching, and would therefore seem more recommendable. Experiments have shown, however, that the gain in speed is marginal. The reason is that the lists are typically quite short. The superiority of a tree structure becomes manifest only when a large number of global objects is declared. We emphasize that when a tree structure is used for each scope, the linear lists must still be present, because the order of declarations is sometimes relevant in interpretation, e.g., in parameter lists. Not only procedures, but also record types establish their own local scope. The list of record fields is anchored in the type record’s field desc, and it is searched by procedure `thisField`. If a record type R1 is an extension of R0, then R1’s field list contains only the fields of the extension proper. The base type R0 is referenced by the BaseTyp field of R1. Hence, a search for a field may have to proceed through the field lists of an entire sequence of record base types. ## Classes - Con = 1 - Var = 2 - Par = 3 - Id = 4 - Typ = 5 Forms: - Byte = 1 - Bool = 2 - Char = 3 - Int = 4 - Lint = 5 - Set = 6 - Pointer = 7 - NotTyp = 8 - ProcTyp = 10 - Array = 12 - Record = 13 ### SymFile SymFile = null; key name version/key(object). object = (CON name type (value | epon) | TYPE name type (fix) | VAR name type (expon)). type = ref (PTR type | ARR type (len) | REC type (field) | PRO type (param)). ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 43 Context: ```markdown Instructions are emitted sequentially and emitted by the four procedures `Put0`, `Put1`, `Put2`, `Put3`. They directly correspond to the instruction formats of the RISC processor (see Chapter 11). The instructions are stored in the array code and the compiler variable `pc` serves as running index. ``` PROCEDURE Put0(op, a: b: INTEGER); format F0 PROCEDURE Put1(op, a: b: IN INTEGER); format F1 PROCEDURE Put2(op, a: b: off: INTEGER); format F2 PROCEDURE Put3(op, cond: off: INTEGER); format F3 ``` ## 12.7.1. Expressions Expressions consist of operands and operators. They are evaluated and have a value. First, a number of make-procedures transform objects into items (see Section 12.3.2). The principal one is `MakeItem`. Typical objects are variables (class, mode = `Var`). Global variables are addressed with base register `SB (xr = 13)`, local variables with the stack pointer `SP (xr = 14)`. `VAR`-parameters are addressed indirectly; the address is on the stack (class, mode = `Par`, `Ind`). `x` is the offset from the stack pointer. Before an operator can be applied to operands, these must first be transferred (loaded) into registers. This is because the RISC performs operations only on registers. The loading is achieved by procedure `load` and `loadAdr` in `ORG`. The resulting mode is `Reg`. In allocating registers, a strict stack principle is used, starting with `R0`, up to `R11`. This is certainly not an optimal strategy and provides ample room for improvement (usually called optimization). The compiler variable `RH` indicates the next free register (top of register stack). Base address `SB` is, as the name suggests, static. But this holds only within a module. It implies that on every transfer to a procedure in another module, the static base must be adjusted. The simplest way is to load `SB` before every external call, and to restore it to its old value after return from the procedure. We chose a different strategy: loading on demand (see below: global variables). If a variable is indexed, has a field selector, is dereferenced, or has a type guard, this is detected in the parser by procedure `selector`. It calls generators `Index`, `Field`, `DeRef`, or `TypeTest` accordingly (see Section 12.3.2 and patterns 1 - 4 in Section 12.2). These procedures cause item nodes to change as follows: 1. **Index(x, y) (y is loaded into x.r)** - `Var -> RegI` `ADD y, SP, y.r` // array variable - `Par -> RegI` `LDR RH, SP, x.a` `ADD y, RH, y.r` // array parameter - `RegI -> RegI` `ADD x, x.r, y.r` // indexed array 2. **Field(x, y) (y.mode = Field, y.a = field offset)** - `Var -> Var` `none` // field designator, add offset to x.a - `RegI -> RegI` `none` // add field offset to x.a - `Par -> none` `add field offset to x.b` 3. **DeRef(x)** - `Var -> RegI` `LDR RH, SP, x.a` // dereferenced x.a - `Par -> RegI` `LDR RH, SP, x.a` `LDR RH, x.b` // dereferenced parameter x.a - `RegI -> RegI` `LDR x.r, x.r, x.a` A fairly large number of procedures then deal with individual operators. Specifically, they are `Not`, `And1`, `And2`, `Or1`, `Or2` for Boolean operators, `Neg`, `AddOp`, `MulOp`, `DivOp` for operations on integers, `RealOp` for operations on real numbers, and `Singleton`, `SetIn`, and `SetOp` for operations. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 45 Context: ```markdown Statements have an effect, but no result like expressions. Statements are executed, not evaluated. Assignments alter the value of variables through store instructions. The computation of the address of the affected variable follows the same scheme as for loading. The value to be assigned must be in a register. Assignments of arrays (and records) are an exceptional case in so far as they are performed not by a single store instruction, but by a repetition. Consider `y = x`, where `x` and `y` are both arrays of `n` integers. Assuming that the address of `y` is in register R0, that of `x` in R1, and the value in R2. Then the resulting code is: ``` LDR R3, R1, 0 ; source ADD R1, R1, 4 ; R1 := R1 + 4 STR R3, R0, 0 ; destination ADD R0, R0, 4 ; R0 := R0 + 4 SUB R2, R2, 1 ; counter BNE L2 ; loop condition ``` ## 12.7.5 Conditional and repetitive statements These statements are implemented using branch instructions (jumps) as shown in Section 12.2, Patterns 5 - 7. In all repetitive statements, backward jumps occur. Here, at the point of return the value of the global variable `ORG.pc` is saved in a local (`l`) variable of the involved parsing procedure. It is retrieved when the backward jump is emitted. We note that branch instructions use a displacement rather than an absolute destination address. It is the difference between the branch instruction and the destination of the jump. A difficulty, however, arises in the case of forward jumps, a difficulty inherent in all single-pass compilers: When the branch is issued, its destination is still unknown. It follows that the branch displacement must be later resolved when it becomes known, when the destination is reached. This is called a `fixup`. Here the method of fixup lists is used. The place of the instruction with still unknown destination is held in a variable `l` localized to the respective parsing procedure. If several branches have the same destination, `l` is the leading of a list of the instructions to be fixed up, with its links placed in the instructions themselves in the place of the eventual jump displacement. This is shown for the statement by an excerpt of `ORP.StaSequence` with local variable `L0`: ``` ELSIF sym = ORS.i THEN ORS.Get(sym); expression(); ORG.FJump(l0); StatSequence: L0 := 0; WHILE sym = ORS.elsi DO ORS.Get(sym); ORG.FJump(L0); ORG.Fixup(x); expression(); ORG.FJump(y); Check(ORS.then, 'no THEN'); StatSequence END; IF sym = ORS.else THEN ORS.FJump(L0); ORG.Fixup(x); StatSequence ELSE ORG.Fixup(y) END; ORG.FixLink(L0); ``` where in module `ORG`: ``` PROCEDURE FJump(VAR x: Item); (*conditional forward jump*) BEGIN IF x.mode <> Cond THEN loadCond(x) END; Push(BC, negated(x), x.a); FLink(x, l0); x.a := pc-1 END FJump; PROCEDURE FJump(VAR x: LONGINT); (*unconditional forward jump*) BEGIN Push(BC, 7); l := L - p - 1 END FJump; PROCEDURE fix(at: WITH LONGINT); BEGIN code[at] := code[at] DIV C24 * C24 + (with MOD C24) END fix; ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 46 Context: ```markdown ## PROCEDURE FixLink(L: LONGINT); VAR L1: LONGINT; BEGIN Invalids: WHILE L <> 0 DO L := code[L] MOD 40000; FixLink(L1); L := L1 END FixLink; ## PROCEDURE Fixup(VAR x: Item); BEGIN FixLink(x.a) END Fixup; In while-, repeat-, and for statements essentially the same technique is used with the support of the identical procedures in `ORG`. ### 12.7. Boolean expressions In the case of arithmetic expressions, our compilation scheme results in a conversion from infix to postfix notation (x+y → x y +). This is not applicable for Boolean expressions, because the operators `&` and `OR` are defined as follows: - `x & y → if x then y else FALSE` - `x OR y → if x then TRUE else y` This entails that depending on the value of `x`, `y` must not be evaluated. As a consequence, jumps may have to be taken across the code for `y`. Therefore, the same technique of conditional evaluation must be used for conditional statements. In the case of an expression `x & (y OR p)`, procedure `ORG.And` resp. `ORG.OR1` must be called just after parsing `x` (see `ORG.Term` resp. `ORG.SimpleExpression`). Only after parsing `y` can the generators `ORG.And2` resp. `ORG.Or2` be called, providing the necessary fixups of forward jumps. ```pascal PROCEDURE And1(VAR x: Item); (* x := x & a *) BEGIN IF x.mode = cond THEN loadCond(x) END; FixUp(x, negated(x.a)); x.a := p; FixLink(x.b); x.b := 0 END And1; PROCEDURE And2(VAR x: Item); BEGIN IF x.mode = cond THEN loadCond(x) END; x.a := merge(d(x.a), x.b); x.b := y; x.r := x.r END And2; ``` A negative consequence of this scheme having condition flags in the processor is that when an item with mode `Cond` has to be transferred into mode `Reg`, as in a Boolean assignment, an unpleasantly complex instruction sequence must be generated. Fortunately, this case occurs quite rarely. ### 12.7.7 Procedures Before embarking on an explanation of procedure calls, entries and exits, we need to know how recursion is handled and how storage for local variables is allocated. Procedure calls cause a sequence of frames to be allocated in a stack fashion. These frames are the storage space for local variables. Each frame is headed by a single word containing the return address of the call. This address is deposited in R15 by the lead instructions (BL, branch and link). The compiler "knows" the size of the frame to be allocated, and thus merely decrements the stack pointer SP (R14) by this amount. Upon return, SP is incremented by the same amount, and PC is restored by a branch instruction. In the following example, a procedure P is called, calling itself Q, and Q calling P again (recursion). The stack then contains 3 frames (see Figure 12.7). ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 47 Context: ```markdown # Stack Frames Scheme and layout determine the code sequences for call, entry, and exit of procedures. Here is an example of a procedure `P` with 2 parameters: ## Call: ``` LDR R0, param0 LDR R1, param1 BL P ``` ## Prolog: ``` SUB SP, SP, size ; decrement SP STR LNK, SP, 0 ; push return addr STR R0, SP, 4 ; push parameter 0 STR R1, SP, 8 ; push parameter 1 .... ``` ## Epilog: ``` LDR LNK, SP, 0 ; pop return addr ADD SP, SP, size ; increment SP BR LNK ``` When the call instruction is executed, parameters reside in registers, starting with R0. For function procedures, the result is passed in register R0. This scheme is very efficient; storing the parameters occurs only in a single place, namely at procedure entry, and not before each call. However, it has severe consequences for the entire register allocation strategy. Throughout the compiler, registers **must** be allocated in strict stack fashion. Furthermore, parameter allocation must start with R0. This is a distinct drawback for function calls. If registers are occupied by other values loaded prior to the call, they must be cleared; i.e., the parameters must be saved and reloaded after return. This is rather cumbersome (see procedures `ORG.SaveRegisters` and `ORG.RestoreRegisters`). ### Register Saving | Expression | Register Saving Needed | |----------------------|--------------------------| | F(x) | no register saving | | F(x + F(x)) | register saving necessary | --- ## Type Extension Static typing is an important principle in programming languages. It implies that every constant, variable, or function is of a certain data type, and that this type can be derived by reading the program text without executing it. It is the key principle to introduce important redundancy in languages in such a form that a compiler can detect inconsistencies. It is therefore the key element for reducing the number of errors in programs. However, it also acts as a restriction. It is, for example, impossible to construct data structures (arrays, trees) with different types of elements. In order to relax the rule of strictly static typing, the notion of type extension was introduced in Oberon. It makes it possible to construct. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 48 Context: ```markdown # Type Safety in Oberon Inhomogeneous data structures without abandoning type safety. The price is that the checking of type consistency must in certain instances be deferred to run-time. Such checks are called *type tests*. The challenge is to defer to run-time as few checks as possible and as many as needed. The solution in Oberon is to introduce families of types, and compatibility among their members. Their members are thus related, and a family forms a hierarchy. The principle idea is the following: Any record type `T0` can be extended into a new type `T1` by additional record fields (attributes). `T1` is then called an *extension* of `T0`, which in turn is said to be `T1`'s *base type*. `T1` is then compatible with `T0`, but not vice-versa. This property ensures that in many cases static type checking is still possible. Furthermore, it turns out that run-time tests can be made very efficient, thus minimizing the overhead for maintaining type safety. For example, given the declarations: ```pascal TYPE R0 = RECORD u: INTEGER END; R1 = RECORD (R0) u: INTEGER END; ``` we say that `R1` is an extension of `R0`. `R0` has the fields `u` and `v`, `R1` has `u`, `v`, and `w`. The concept becomes useful in combination with pointers. Let ```pascal TYPE P0 = POINTER TO R0; P1 = POINTER TO R1; VAR p0: P0; p1: P1; ``` Now it is impossible to assign `p0` to `p0` (because a `P1` is always also a `P0`), but not `p0` to `p1`, because a `P0` need not be a `P1`. This has the simple consequence that a variable of type `P0` may well point to an extension of `R0`. Therefore, data structures can be declared with a base type `P0`, as common element type, but in fact they can individually differ; they can be any extension of the base type. Obviously, it must be possible to determine the actual, current type of an element even if the base type is statically fixed. This is possible through a *type test*, syntactically a Boolean factor: ```pascal p0 IS P1 ``` (short for `p0 IS R1`) Furthermore, we introduce the *type guard*. In the present example, the designator `p0^` is illegal, because there is no field `v` in a record of type `P0`, even if the current value of `p0^` is a `R1`. As this case occurs frequently, we introduce the short notation `p0(P1^),` implying a test `p0 IS P1` and an abort if the test is not met. It is important to mention that this technique also applies to formal variable parameters of record type, as they also represent a pointer to the actual parameter. Its type may be any extension of the type specified for the formal parameter in the procedure heading. ## Implementation of Type Test and Type Guard How are type test and type guard efficiently implemented? Our first observation is that they must consist of a single comparison only, similar to index checks. This in turn implies that types must be identified by a single word. The solution lies in using the unique address of the type descriptor or the *record* type. Which data must this descriptor hold? Essentially, type descriptors (TD) must identify the base types of a given type. Consider the following hierarchy: ```pascal TYPE T = RECORD ... END; T0 = RECORD (T) ... END; // extension level 1 T1 = RECORD (T) ... END; // extension level 1 T00 = RECORD (T0) ... END; // extension level 2 T01 = RECORD (T0) ... END; // extension level 2 T10 = RECORD (T1) ... END; // extension level 2 T11 = RECORD (T1) ... END; // extension level 2 ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 49 Context: ```markdown # Figure 12.8: A type hierarchy In the symbol table, the field base refers to the ancestor of a given record type. Thus base of the type representing T11 points to T1, etc. Run-time checks, however, must be last, and hence cannot proceed through chains of pointers. Instead, each TD contains an array with references to the ancestor TDs (including itself). For the example above, the TDs are as follows: - `TD(T)` = `[]` - `TD(T0)` = `[T, T1]` - `TD(T1)` = `[T, T]` - `TD(T00)` = `[T, T0]` - `TD(T01)` = `[T, T0, T1]` - `TD(T10)` = `[T, T1]` - `TD(T11)` = `[T, T1, T1]` Evidently, the first element can be omitted, as it always refers to the common base of the type hierarchy. The last element always points to the TD's owner. TDs are allocated in the data area, the area for variables. References to TDs are called **type tags**. They are required in two cases. The first is for records referenced by pointers. Such dynamically allocated records carry an additional, hidden field holding their type tag. (A second additional word is reserved for use by the garbage collector. The offset of the tag field is therefore -8.) The second case is that of record-typed VAR-parameters. In this case, the type tag is explicitly passed along with the address of the actual parameter. Such parameters therefore require two words/registers. A type test consists of a test for equality of two type tags. In `P` the first tag is that of the nth entry of the TD of `p^`, where `n` is the extension level of `T`. The second tag is that of type `T`. This is shown in Pattern1 in Section 12.2 (see also Fig. 12.4). The test then is as follows: ``` P.tag[`T`] = addr(`T`), where n is the extension level of `T` ``` When declaring a record type, it is not known how many extensions, or how many levels will be built on this type. Therefore TDs should actually be infinite arrays. We decided to restrict them to 3 levels only. The first entry, which is never used for checking, is replaced by the size of the record. ## 12.7.9. Import and export, global variables Addresses of imported objects are not available to the compiler. Their computation must be left to the module loader (see Chapter 6). Similar to handling addresses of forwarding modules, the compiler puts the necessary information in place of the actual address into the instruction itself. In the case of procedure calls, this is quite feasible, because the BL instruction features an offset field of 24 bits. The information consists of the module number and the export number of the imported object. In addition, there is a link to the previous instruction referring to an imported procedure. The origin of the first procedure called by your linker is rooted in the compiler variable `xorg`, and the 24 bits in each BL instruction 4 bits are used for the module number, 8 bits for the object's export number, and 12 for the link. The loader need only scan this list to fix up the addresses (jump offsets). Matters are more complex in the case of data. Object records in the symbol table have a field `E`. It indicates the nesting level of variables local to procedures. It is also used for the module number in the case of variables of imported modules. Note that when importing, objects designating modules are inserted in the symbol table, and the list of their own objects are attached in the field `dsc`. In this manner, the information can be structured efficiently. 49 ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 50 Context: ```markdown latter case, the module numbers have an inverted sign (are negative). Such imported objects are static, i.e., have a fixed address. In principle, their absolute address could be computed (fixed) by the module loader. However, this is not practicable, because RISC instructions have an address offset of 16 bits only. It is therefore necessary in the general case to use a base address in conjunction with the offset. We use a single register for holding the static base (SB, R13). This register need be reloaded for every access to an imported variable. However, the compiler keeps track of external accesses; if a variable is to be accessed from the same module as the previous case, then reloading is avoided (see procedure GetSB and global compiler variable curSB). This base address is fetched from a table global to the entire system. This module table contains one entry for every module loaded, namely the address of the module's data section. The address of the table is permanently in register MT (R12). An access to an imported variable therefore always requires two instructions: ``` LDR SB, MT, mod+0 ; base address of data section LDR SB, offset ; offset computed by the loader from object's export number ``` Considering the fact that references to external variables are (or should be) rare, this circumstance is of no great concern. (Note also that such accesses are read-only). More severe is the fact that we also treat global variables contained in the same module by the same technique. Their level number is 0. One might use a specific base register for the base of the current module. Its content would then have to be reloaded upon every procedure call and after every return. This is common technique, but we have chosen to reload only when necessary, i.e., only when an access is at hand. This strategy rewards the programmer who sensibly uses global variables rarely. ## 12.7. Traps This compiler provides an extensive system of safeguard by providing run-time checks (aborts) in several cases: | trap number | trap cause | |-------------|----------------------------------| | 1 | array index out of range | | 2 | type guard failure | | 3 | array or string copy overflow | | 4 | access via NIL pointer | | 5 | illegal procedure call | | 6 | integer division by zero | | 7 | assertion violated | These checks are implemented very efficiently in order not to downgrade a program's performance. Involved is typically a single compare instruction, plus a conditional branch (BLR MT). It is assumed that entry 0 of the module table contain not a base address (module numbers start with 1), but a branch instruction to an appropriate trap routine. The trap number is encoded in bits 47:0 of the branch instruction. The predefined procedure `Assert` generates a conditional trap with trap number 7. For example, the statement `Assert(m = n)` generates: ``` LDR RO, m ; load m LDR R1, n ; load n CMP RO, R0 ; branch if unequal through R12, trap number 7 BLR R1, 7 ; CH ``` Procedure `New`, representing the operator `NEW`, has been implemented with the aid of the trap mechanism. (This is in order to omit in ORG any reference to module `Kernel`, which contains the allocation procedure `New`). The generated code for the statement `NEW(p)` is: ``` ADD RO, SP, p ; address of p ADD R1, SB, tag ; tag type BLR R7, 0CH ; branch and link unconditionally through R12 (MT), trap number 0 ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 51 Context: ```markdown # 13 A graphics editor ## 13.1 History and goal The origin of graphics systems as they are in use at this time was intimately tied to the advent of the high-resolution bit-mapped display and of the mouse as pointing device. The author's first contact with such equipment dates back to 1976. The Alto computer at the Xerox Palo Alto Research Center is justly termed the first workstation featuring those characteristics. The designer of its first graphics package was Ch. Thacker who perceived the usefulness of the high-resolution screen for drawing and processing schematics of electronic circuits. This system was cleverly tailored to the needs encountered in this activity, and it was remarkable in its compactness and effectiveness due to the lack of unnecessary facilities. Indeed, its acronym was SIl, for Simple Illustrator. After careful study of the used techniques, the author designed a variant, programmed in Modula-2 (instead of BCPL) for the PDP-11 Computer, thereby ordering and exhibiting the involved data structures more explicitly. In intervals of about two years, that system was revised and grew gradually into the present Draw system. The general goal remained a simple line drawing system: emphasis was placed on a clear structure and increase of flexibility through generalization of existing rather than indiscriminate addition of new features. In the history of this evolution, three major transitions can be observed. The first was the move from a single "window," the screen, to multiple windows showing different excerpts of the same graphic. This step was performed on the Lilith computer which resembled the Alto in many ways. The second major transition was the application of the object-oriented style of programming, which allowed the addition of new element types to the basic system, making it extensible. The third step concerned the proper integration of the Draw system with Oberon's text system. The last two steps were performed using Oberon and the Ceres computer. We refrain from exhibiting this evolution and merely present the outcome, although the history might be an interesting reflection of the evolution of programming techniques in general, containing many useful lessons. We stress the fact, however, that the present system rests on a long history of development, during which many features and techniques were introduced and later discarded or revised. The size of the system's description is a poor measure of the effort that went into its construction; deletion of program text sometimes marks bigger progress than addition. The goal of the original SIl program was to support the design of electronic circuit diagrams. Primarily, SIl was a line drawing system. This implies that the drawings remain uninterrupted. However, in a properly integrated system, the addition of modules containing operators that interpret the drawings is a reasonably straightforward proposition. In fact, the Oberon system is ideally suited for such steps, particularly due to its command facility. At first, we shall ignore features specially tailored to circuit design. The primary one is a macro facility to be discussed in a later chapter. The basic system consists of the modules Draw, GraphicFrames, and Graphics. These modules contain the facilities to generate and handle horizontal and vertical lines, text captions, and macros. Additional modules serve to introduce other elements, such as rectangles and circles, and the system is extensible. Further modules may be introduced to handle further types of elements. ## 13.2 A brief guide to Oberon's line drawing system In order to provide the necessary background for the subsequent description of the Draw system's implementation, a brief overview is provided in the style of a user's guide. It summarizes the facilities offered by the system and gives an impression of its versatility. The system called Draw serves to prepare line drawings. They contain lines, text captions, and other items, and are displayed in graphic viewers (more precisely: in menu viewer's graphic frames). ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 52 Context: ```markdown # Graphic Viewer The graphic viewer shows an excerpt of the drawing plane, and several viewers may show different parts of a drawing. The most frequently used commands are built-in as mouse clicks and combinations of clicks. Additional commands are selectable from texts, either in viewer menus (title bars) or in the text called **Draw Tool**. Fig. 13.1 shows the display with two graphic viewers at the left and the draw tool text at the right. The mouse buttons have the following principal functions whenever the cursor lies in a graphic frame: | Left | Middle | Right | |-----------------|------------------|-------------| | draw / set caret| move / copy | select | ## 13.2.1 Basic Commands The command `Draw.Open` opens a new viewer and displays the graph with the name given as a parameter. We suggest that file names use the extension `.graph`. **Drawing a line.** In order to draw a horizontal or vertical line from P0 to P1, the left key is pressed with the cursor at P0 and, while the key is held, the mouse and cursor is moved to P1. Then the key is released. If P0 and P1 differ in both their x and y coordinates, the end point is adjusted so that the line is either horizontal or vertical. **Writing a caption.** First the cursor is positioned where the caption is to appear. Then the left key is clicked, causing a crosshair to appear. It is called the caret. Then the text is typed. Only single lines of texts are accepted. The `DEL` key may be used to retract characters (backspace). **Selecting.** Most commands require the specification of operands, and many implicitly assume the previously selected elements - the **selection** - to be their operands. A single element is selected by pointing at it with the cursor and then clicking the right mouse button. This also causes previously selected elements to be deselected. If the left key is also clicked, their selection is retained. This action is called an **interclick**. To select several elements at once, the cursor is moved from P0 to P1 while the right key is held. Then all elements lying within the rectangle with diagonally opposite corners at P0 and P1 are selected. Selected lines are displayed as dotted lines, selected captions (and macros) by inverse video mode. A macro is selected by pointing at its lower left corner. The cursor is called **sensitive area**. **Moving.** To move (displace) a set of elements, the elements are first selected and then the cursor is moved from P0 to P1 while the middle key is held. The vector from P0 to P1 specifies the movement and is called the **displacement vector**. P0 and P1 may lie in different viewers displaying the same graph. Small displacements may be achieved by using the keyboard's cursor keys. **Copying.** Similarly, the selected elements may be copied (duplicated). In addition to pressing the middle key indicating the displacement vector, the left key is interclicked. The copy command may also be used to copy elements from one graph into another graph by moving the cursor from one viewer into another viewer displaying the destination graph. A text item may be copied from a text frame into a graphic frame and vice-versa. There exist two ways to accomplish this: 1. First the caret is placed at the destination position, then the text is selected and the middle key is interclicked. 2. First the text is selected, then the caret is placed at the destination position and the middle key is interclicked. **Shifting the plane.** You may shift the entire drawing plane behind the viewer by specifying a displacement vector pressing the middle button (like in a move command) and interclicking the right button. The following table shows a summary of the mouse actions: | Left | Action | |------------------|----------------| | draw | line | | left (no motion) | set caret | ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 53 Context: ```markdown # 13.2. Menu commands The following commands are displayed in the menu (title bar) of every graphic viewer. They are activated by being pointed at and by clicking the middle button. | Command | Description | |------------------|-----------------------------------------------------| | Draw.Delete | The selected elements are deleted. | | Draw.Store | The drawing is written as file with the name shown in the title bar. | | | The original file is renamed by appending ".Bak". | | Draw.Restore | The entire frame is redrawn. | | Draw.Ticks | The frame displays a pattern of dots (ticks) to facilitate positioning. | The two viewers in Fig. 13.1 display different parts of the same graphic. The second view was obtained from the generic `System.Copy` command and a subsequent shift of the drawing plane. ![](Figure_13_1_Display_with_graphics_duplicated_viewers.png) Figure 13.1: Display with graphics duplicated viewers ## 13.2.3. Further commands The following commands are listed in the text `Draw.Tool`, but may appear in any text. | Command | Description | |------------------|----------------------------------------------------| | Draw.Store name | The drawing in the marked viewer is stored as a file with the specified name. | ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 54 Context: ```markdown The subsequent commands change attributes of drawing elements, such as line width, text font, and color, and they apply to the most recent selection. ```plaintext Draw.SetWidth w default = 1, 0 < w < 7. Draw.ChangeFont fontname Draw.ChangeColor c Draw.ChangeWidth w (0 < w < 7) ``` The `ChangeColor` command either takes a color number in the range of 1 to 15 or a string as a parameter. It serves to copy the color from the selected character. ### 13.2.4. Macros A macro is a (small) drawing that can be identified as a whole and used as an element within a (larger) drawing. Macros are typically stored in collections called libraries, from where they can be selected and copied individually. **Draw.Macro lib mac**: The macro `mac` is selected from the library named `lib` and inserted in the drawing at the caret's position. An example for the use of macros is drawing electronic circuit diagrams. The basic library file containing frequently used TTL components is called `TTLO.Lib`, and a drawing showing its elements is called `TTLO.Graph` (see Figure 13.2). ![Figure 13.2 Viewer with circuit macros of TTL library](path/to/your/image) ### 13.2.5. Rectangles Rectangles can be created as individual elements. They are frequently used for framing sets of elements. Rectangles consist of four lines which are selectable as a unit. The attribute commands `Draw.SetWidth`, `System.SetColor`, `Draw.ChangeWidth`, and `Draw.ChangeColor` also apply to rectangles. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 55 Context: ```markdown rectangles. Rectangles are selected by pointing at their lower left corner and are created by the following steps: 1. The caret is placed where the lower left corner of the new rectangle is to lie. 2. A secondary caret is placed where the opposite corner is to lie (ML + MR). 3. The command `Rectangles.Make` is activated. ## 13.2.6. Oblique lines, circles, and ellipses Further graphic elements are (oblique) lines, circles, and ellipses. The sensitive area of circles and ellipses is at their lowest point. They are created by the following steps: ### Lines: 1. The caret is placed where the starting point is to lie. 2. A secondary caret is placed at the position of the end. 3. The command `Curves.MakeLine` is activated. ### Circles: 1. The caret is placed where the circle's center is to lie. 2. A secondary caret is placed, its distance from the center specifying the radius. 3. The command `Curves.MakeCircle` is activated. ### Ellipses: 1. The caret is placed where the center is to lie. 2. A second caret is placed. Its horizontal distance from the first caret specifies one axis. 3. A third caret is placed. Its vertical distance from the first caret specifies the other axis. 4. The command `Curves.MakeEllipse` is activated. ## 13.2.7. Spline curves Spline curves are created by the following steps: 1. The caret is placed where the starting point is to lie. 2. Secondary carets are placed at the spline's fixed points (at most 20). 3. The command `Splines.MakeOpen` or `Splines.MakeClosed` is activated. ## 13.2.8. Constructing new macros A new macro is constructed and inserted in the library `lib` under the name `mac` as follows: 1. All elements which belong to the new macro are selected. 2. The caret is placed at the lower left corner of the area to be spanned by the macro. 3. A secondary caret is placed at the upper right corner of the area to be spanned. 4. The command `MacroTool.MakeMacro lib` is activated. An existing macro can be decomposed (opened) into its parts as follows: 1. The macro is selected. 2. The caret is placed at the position where the decomposition is to appear. 3. The command `MacroTool.OpenMacro` is activated. The command `MacroTool.StoreLibrary lib` first stores the library `lib` on the specified file. Only macros presently loaded are considered as belonging to the library. If one wishes to add macros to an existing library file, all of its elements must first be loaded. This is best done by opening a graph containing all macros of the desired library file. ## 13.3. The core and its structure Like a text, a graphic consists of elements, subsequently to be called objects. Unlike a text, which is a sequence of elements, a graphic is an unordered set of objects. In a text, the position of an element need not be explicitly indicated (stored); it is recomputed from the position of its predecessor each time it is needed, for example for displaying or selecting an element. In a graphic, each object must carry its position explicitly, as it is independent of any other object in the set. This is an essential difference, requiring a different treatment and much more storage space for an equal number of objects. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 57 Context: ```markdown ## PROCEDURE drawObj(obj: Object); BEGIN IF obj IS Line THEN drawLine(obj(Line)); ELSIF obj IS Caption THEN drawCaption(obj(Caption)); ELSE (* other object types, if any *) END; END drawObj; ## PROCEDURE drawGraphic(first: Object); VAR obj: Object; BEGIN obj := first; WHILE obj <> NIL DO drawObj(obj); obj := obj.next; END; END drawGraphic; The two procedures typically are placed in different modules, one containing operations on objects, the other those on graphics. Here the former is the service module, the latter the former's client. Procedures for, e.g., copying elements, or determining whether an object is selectable, follow the same pattern as `drawGraphic`. This solution has the unpleasant property that all object types are anchored in the base module. If any new types are to be added, the base module has to be modified (and all clients are to be - at least - recompiled). The object-oriented paradigm eliminates this difficulty by inverting the roles of the two modules. It rests on binding the operations pertaining to an object type to each object individually in the form of procedure-typed record fields as shown in the following sample declaration: ``` ObjectDesc = RECORD x, y: INTEGER; selected: BOOLEAN; draw: PROCEDURE (obj: Object); write: PROCEDURE (obj: Object; VAR r: Files.Rider); next: ObjectDesc; END; ``` The procedure `drawGraphic` is now formulated as follows: ```pascal PROCEDURE drawGraphic(first: Object); VAR obj: Object; BEGIN obj := first; WHILE obj <> NIL DO drawObj(obj); obj := obj.next; END; END drawGraphic; ``` The individual procedures - in object-oriented terminology called **methods** - are assigned to the record's fields upon its creation. They need no further discrimination of types, as this role is assumed by the assignment of the procedures upon their installation. We note here that the procedure fields are never changed; they assume the role of **constants** rather than variables associated with each object. This example exhibits in a nutshell the essence of object-oriented programming, extensibility as its purpose and the procedure-typed record field as the technique. The given solution, as it stands, has the drawback that each object (instance, variable) contains several procedures (of which three are listed), and therefore leads to a storage requirement that should be avoided. Furthermore, it defines once and for all the number of operations applicable to objects, and also their parameters and result types. A different approach with the same underlying principle removes these drawbacks. It employs a single installed procedure which itself discriminates among the operations according to different types of parameters. The parameters of the preceding solution are merged into a single record called a message. The unified procedure is called a **handler**, and messages are typically extensions of a single base type `Msg`. ``` TYPE Msg = RECORD END; DrawMsg = RECORD (Msg) END; WriteMsg = RECORD (Msg R.Files.Rider END); ObjectDesc = RECORD x, y, w, col: INTEGER; selected: BOOLEAN; END; ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 58 Context: ```markdown handle: PROCEDURE (obj: Object; VAR M: Msg); next: Object END; PROCEDURE Handle (obj: Object; VAR M: Msg); BEGIN (* this procedure is assigned to the handle field of every line object *) IF M.IsDrawMsg THEN drawLine(obj)(Line) ELSIF M.IsWriteMsg THEN writeLine(obj)(Line), M(WriteMsg).R ELSE ... END END; PROCEDURE drawGraphic(first: Object; VAR M: Msg); VAR obj: Object; BEGIN obj := first; WHILE obj <> NIL DO obj.handle(obj, M); obj := obj.next END END drawGraphics; In the present system, a combination of the two schemes presented so far is used. It eliminates the need for individual method fields in each object record as well as the cascaded IF statement for discriminating among the message types. Yet it allows further addition of new methods for later extensions without the need to change the object's declaration. The technique used is to include a single field (called obj) in each record (analogous to the handler). This field is a pointer to a method record containing the procedures declared for the base type. At least one of them uses a message parameter, i.e., a parameter of record structure that is extensible. TYPE Method = POINTER TO MethodDesc; Msg = RECORD END; Context = RECORD END; Object = POINTER TO ObjectDesc; ObjectDesc = RECORD x, y: INTEGER; selected: BOOLEAN; method: NEXT: Object END; MethodDesc = RECORD new: Modules.Command; copy: PROCEDURE (obj: Object); draw: handle: PROCEDURE (obj: Object; VAR M: Msg); selectable: PROCEDURE (obj: Object; x, y: INTEGER): BOOLEAN; read: PROCEDURE (obj: Object; VAR R: Files.Rider; VAR C: Context); write: PROCEDURE (obj: Object; con: INTEGER; VAR R: Files.Rider; VAR C: Context); END; A single method instance is generated when a new object type is created, typically in the initialization sequence of the concerned module. When a new object is created, a pointer to its record is assigned to the obj field of the new object descriptor. A call then has the form obj^.write(obj, R). This example exhibits the versatility of Oberon's type extension and procedure variable features very well, and it does so without hiding the data structures involved in a dispensable, built-in run-time mechanism. The foregoing deliberations suggest the system's modular structure shown in Figure 13.3: ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 60 Context: ```markdown The set of operations applying to selected objects only consist of the following procedures: `Deselect`, `DrawSel` (drawing the selection according to a specified mode), `Change` (changing certain attributes of selected objects like width, font, color), `Move`, `Copy`, `CopyOver` (copying from one graphic into another), and finally `Delete`. Also, there exists the important procedure `Open` which creates a new graphic, either loading a graphic stored as a file, or generating an empty graphic. The declaration of types and procedures that have emerged so far are summarized in the following excerpt of the module’s interface definition. ```pascal DEFINITION Graphics; (* excerpt without macros *) IMPORT Files, Fonts, Texts, Modules, Display; CONST NameLen = 32; TYPE Graph = POINTER TO GraphDesc; Object = POINTER TO ObjectDesc; Method = POINTER TO MethodDesc; ObjectDesc = RECORD x, y: INTEGER; c: BYTE; selected, marked: BOOLEAN; de: Method END; Msg = RECORD END; WildMsg = RECORD (Msg) w: INTEGER END; ColorMsg = RECORD (Msg) col: INTEGER END; FontMsg = RECORD (Msg) font: Fonts.Font END; Name = ARRAY NameLen OF CHAR; GraphDesc = RECORD sel: Object; time: INTEGER END; Context = RECORD END; MethodDesc = RECORD module, allocator: Name; new: Modules.Command; copy: PROCEDURE (obj: Object); draw: change: PROCEDURE (obj: Object; VAR msg: Msg); selectable: PROCEDURE (obj: Object; x, y: INTEGER): BOOLEAN; read: PROCEDURE (obj: Object; VAR R: Files.Rider; VAR C: Context); write: PROCEDURE (obj: Object; cno INTEGER; VAR R: Files.Rider; VAR C: Context); END; Line = POINTER TO LineDesc; LineDesc = RECORD (ObjectDesc) END; Caption = POINTER TO CaptionDesc; CaptionDesc = RECORD (ObjectDesc) pos, len: INTEGER END; VAR width, res: INTEGER; T: Texts.Text; PROCEDURE New(obj: Object); PROCEDURE Add(G: Graph; obj: Object); PROCEDURE Draw(G: Graph; VAR M: Msg); PROCEDURE ThisObj(G: Graph; x, y: INTEGER): Object; PROCEDURE Select(G: Graph; obj: Object); PROCEDURE SelectArea(G: Graph; x0, x1, y0, y1: INTEGER); PROCEDURE Deselect(G: Graph); PROCEDURE DrawSel(G: Graph; VAR M: Msg); ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 62 Context: ```markdown # Figure 13.4 Frame and graph coordinates As a consequence, the display coordinates \( u, v \) of an object \( z \) of a graph displayed in a frame \( f \) are computed as: \[ u = z.x + f.x, \quad v = z.y + f.y \] In order to determine whether an object \( z \) lies within a frame \( f \), the following expression must hold: \[ (f.x < u \leq f.x + f.w) \& (f.y < v \leq f.y + f.h) \] The record field `marked` indicates whether or not the frame contains a caret. Its display position is recorded in the field called `mark`. A frame may contain several (secondary) carets; they form a list of individual location descriptors. When an object is displayed (drawn), its state must be taken into consideration in order to provide visible user feedback. The manner in which selection is indicated, however, may vary among different object types. This can easily be realized because every object (type) is associated with an individual drawing procedure. The following visualizations of selection have been chosen: - Selected lines are shown in a grey tone (raster pattern). - Selected captions are shown with "inverse video". Change of state is a relatively frequent operation, and if possible a complete repainting of the involved objects should be avoided for reasons of efficiency. Therefore, procedures for drawing an object are given a mode parameter, in addition to the obvious object and frame parameters. The parameters are combined into the message record of type `DrawMsg`. ```pascal DrawMsg = RECORD (Graphics.Msg) f: Frame; mode: x, y, col: INTEGER; END; ``` The meaning of the mode parameter's four possible values are the following: - **mode = 0**: draw object according to its state, - **mode = 1**: draw reflecting a transition from normal to selected state, - **mode = 2**: draw reflecting a transition from selected to normal state, - **mode = 3**: erase. In the case of captions, for instance, the transitions are indicated by simply inverting the rectangular area covered by the caption. No rewriting of the captions' character patterns is required. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 63 Context: ```markdown A mode parameter is also necessary for reflecting object deletion. First, the selected objects are drawn with mode indicating erasure. Only afterwards are they removed from the graphic's linked list. Furthermore, the message parameter of the drawing procedure contains two offsets `x` and `y`. They are added to the object's coordinates, and their significance will become apparent in connection with macros. The same holds for the color parameter. The drawing procedures are fairly straightforward and use the four basic raster operations of module `Display`. The only complication arises from the need to clip the drawing at the frame boundaries. In the case of captions, a character is drawn only if it fits into the frame in its entirety. The raster operations do not test (again) whether the indicated position is valid. At this point we recall that copies of a viewer (and its frames) can be generated by the `System.Copy` command. Such copies display the same graphic, but possibly different excerpts of them. When a graphic is changed by an insertion, deletion, or any other operation, at a place that is visible in several frames, all affected views must reflect the change. A direct call to a drawing procedure indicating a frame and the change does therefore not suffice. Here again, the object-oriented style solves the problem neatly: In place of a direct call a message is broadcast to all frames, the message specifying the nature of the required updates. The broadcast is performed by the general procedure `Viewers.Broadcast(M)`. It invokes the handlers of all viewers with the parameter `M`. The viewer handlers either interpret the message or propagate it to the handlers of their subframes. Procedure `obj.handle` is called with a control message as parameter when pointing at the object and clicking the middle mouse button. This allows control to be passed to the handler of an individual object. The definition of module `GraphicFrames` is summarized by the following interface: ```modula-2 DEFINITION GraphicFrames; IMPORT Display, Graphics; TYPE Frame = POINTER TO FrameDesc; Location = POINTER TO LocDesc; LocDesc = RECORD x, y: INTEGER; next: Location END; FrameDesc = RECORD (Display.FrameDesc) graph: Graphics.Graph; xg, Y1, Y1: x, y: INTEGER; marked, clicked: BOOLEAN; mark: LocDesc END; (* mode = 0 -> draw according to selected, 1: normal -> selected, 2: selected -> normal, 3: erase *) DrawMsg = RECORD (Graphics.Msg) t: Frame; x, y, col, mode: INTEGER END; PROCEDURE Restore (F: Frame); PROCEDURE Focus (F: Frame); PROCEDURE Selected (F: Frame); PROCEDURE ThisX (x: INTEGER; F: Frame); PROCEDURE Draw (F: Frame); PROCEDURE Erase (F: Frame); PROCEDURE DrawObj (F: Frame; obj: Graphics.Obj); PROCEDURE EraseObj (F: Frame; obj: Graphics.Obj); PROCEDURE Change (F: Frame; VAR msg: Graphics.Msg); PROCEDURE Decease (F: Frame); PROCEDURE Deselect (F: Frame); PROCEDURE Macro (VAR Lname, Mname: ARRAY OF CHAR); ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 65 Context: ```markdown # 13.6. Macros For many applications, it is indispensable that certain sets of objects may be named and used as objects themselves. Such a named subgraph is called a **macro**. A macro thus closely mirrors the sequence of statements in a program that is given a name and can be referenced from within other statements: the procedure. The notion of a graphic object becomes recursive, too. The facility of recursive objects is so fundamental that it was incorporated in the base module **Graphics** as the third class of objects. Its representation is straightforward: in addition to the attributes common to all objects, a field is provided storing the head of the list of elements which constitute the macro. In the present system, a special node is introduced representing the head of the element list. It is of type `MacHeadDesc` and carries also the name of the macro and the width and height of the rectangle covering all elements. These values serve to speed up the selection process, avoiding their recomputation by scanning the entire element list. The recursive nature of macros manifests itself in recursive calls of display procedures. In order to draw a macro, drawing procedures of the macro's element types are called (which may be macros again). The coordinates of the macro are added to the coordinates of each element, which function as offsets. The color value of the macro, also a field of the parameter of type `DrawSwg`, overrides the colors of the elements. This implies that macros always appear monochrome. An application of the macro facility is the design of schematics of electronic circuits. Circuit components correspond to macros. Most components are represented by a rectangular frame and by labeled connectors (pins). Some of the most elementary components, such as gates, diodes, transistors, resistors, and capacitors are represented by standardized symbols. Such symbols, which may be regarded as forming an alphabet of electronic circuit diagrams, are appropriately provided in the form of a special font, i.e., a collection of raster patterns. Three such arrows are shown in Figure 13.5, together with the components from which they are assembled. The definitions of the data types involved are: ``` Macro = POINTER TO MacroDesc; MacroDesc = RECORD (ObjectDesc) mac: MacHead END; MacHead = POINTER TO MacHeadDesc; MacHeadDesc = RECORD name: Name; w: INTEGER; lib: Library END; Library = POINTER TO LibraryDesc; LibraryDesc = RECORD name: Name END; ``` Procedure `DrawMac(mh, m)` displays the macro with head `mh` according to the draw message parameter **m** which specifies a frame, a position within the frame, a display mode, and an overriding color. In the majority of applications, macros are not created by their user, but are rather provided from another source, in the case of electronic circuits typically by the manufacturer of the components represented by the macros. As a consequence, macros are taken from a collection (inappropriately) called a **library**. In our system, a macro is picked from such a collection by the command `DrawMacro` with a library name and a macro name as parameters. It inserts the specified macro at the place of the caret by calling `GraphicFrames.Macro`, which in turn calls `Graphics.Add`. At last, we mention that selection of a macro is visualized by covering with a dot pattern the entire rectangular area occupied by the macro. This emphasizes the fact that the macro constitutes an object as a whole. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 66 Context: ```markdown The design of new macros is a relatively rare activity. Macros are used rather like characters of a font; the design of new macros and fonts is left to the specialist. Nevertheless, it was decided to incorporate the ingredients necessary for macro design in the basic system. They consist of a few procedures only which are used by a tool module called `MacroTool` (see Section 16.3). `MakeMac` integrates all elements lying within a specified rectangular area into a new macro. `OpenMac` reverses this process by disintegrating the macro into its parts. `InsertMac` inserts a specified macro into a library. `NewLib` creates a new, empty library, and `StoreLib` generates a library file containing all macros currently loaded into the specified library. The details of these operations may be examined in the program listings provided later in this chapter. Summarizing, the following procedures are exported from module `Graphics` related to handling macros: ``` PROCEDURE GetLibName(VAR Name: ARRAY OF CHAR; replace: BOOLEAN; VAR Lib: Library); PROCEDURE ThisLib(VAR Library: Mname: ARRAY OF CHAR; Machead); PROCEDURE DrawMac(M: Machead; VAR M: Msg); ``` and the following are added for creating new macros and libraries: ``` PROCEDURE NewLib(Name: ARRAY OF CHAR; VAR Library); PROCEDURE StoreLib(VAR Library: Library; Fname: ARRAY OF CHAR); PROCEDURE RemoveLibraries; PROCEDURE Open(mac: Machead; G: Graph; x, y: INTEGER); PROCEDURE MakeMac(G: Graph; x, y: INTEGER; Mname: ARRAY OF CHAR; Machead); PROCEDURE MakeMacG(mac: Machead; L: Library; VAR new: BOOLEAN); PROCEDURE InsertMac(mac: Machead; L: Library; VAR new: BOOLEAN); ``` ## 13. Object classes Although surprisingly many applications can be covered satisfactorily with the few types of objects and the few facilities described so far, it is nevertheless expected that a modern graphics system allow the addition of further types of objects. The emphasis lies here on the avoidance instead of change. New facilities are to be providable by the inclusion of new modules without requiring any kind of adjustment, not even recompilation of the existing modules. In practice, their source code would quite likely not be available. It is the triumph of the object-oriented programming technique that this is elegantly possible. The means are the extensible record type and the procedure variable, features of the programming language, and the possibility to load modules on demand from statements within a program, a facility provided by the operating environment. We call, informally, any extension of the type `Object` a class. Hence, the types `Line`, `Caption`, and `Macro` constitute classes. Additional classes can be defined in other modules importing the type `Object`. In every such case, a set of methods must be declared and assigned to a variable of type `MethodDesc`. They form a so-called method suite. Every such module must also contain a procedure, typically a command, to generate a new instance of the new class. This command, likely to be called `Make`, assigns the method suite to the field of the new object. This successful decoupling of additions from the system's base suffices, almost. Only one further kink is unavoidable: When a new graphic, containing objects of a class not defined in the system's core, is loaded from a file, then that class must be identified, the corresponding module with its handlers must be loaded - this is called dynamic loading - and the object must be generated (allocated). Because the object in question does not already exist at the time of reading the object's attribute values, the generating procedure cannot possibly be installed in the same object; it cannot be a member of the method suite. We have chosen the following solution to this problem: 1. Every new class is implemented in the form of a module, and every class is identified by its module name. Every such module contains a command whose effect is to allocate an object of the class, to assign the message suite to it, and to assign the object to the global variable `Graphics.new`. 2. When a graphics file is read, the class of each object is identified and a call to the respective module's allocation procedure derives the desired object. The call consists of two parts: a call to `Modules.ThisMod`, which may cause the loading of the respective class module M, and a call of ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 69 Context: ```markdown The frame handler receiving a consume message interprets the request through procedure `InsertChar`, and receiving a track message through procedure `Edit`. If no mouse key is depressed, the cursor is simply drawn, and thereby the mouse is tracked. Instead of the regular arrow, a crosshair is used as cursor pattern. Thereby immediate visual feedback is provided to indicate that mouse actions are interpreted by the graphics handler (instead of, e.g., a text handler). Such feedback is helpful when graphic frames appear not only in a menu viewer, but as subframes of a more highly structured document frame. Procedure `Edit` first tracks the mouse while recording further key activities (interlocks) until all keys are released. The subsequent action is determined by the perceived key clicks. The actions are (the second key denotes the interlock): - **keys = left,** set caret, if mouse was not moved, otherwise draw new line, - **keys = left, middle** copy text selection to caret position, - **keys = left, right** set secondary caret (mark), - **keys = middle** move selection, - **keys = middle, left** copy selection, - **keys = middle, right** shift origin of graph, - **keys = right** select (either object or objects in area), - **keys = right, middle** copy selected text to caret position. When copying or moving a set of selected objects, it must be distinguished between the cases where the source and the destination graphics are the same or are distinct. In the former case, source and destination positions may lie in the same or in different frames. Procedure `InsertChar` handles the creation of new caption. The actual character string is appended to the global text `T`, and the new object records its position within `T` and its length. A complication arises because the input process consists of as many user actions as there are characters, and because other actions may possibly intervene between the typing. It is therefore unavoidable to record an insertion state, which is embodied by the global variable `newcap`. When a character is typed, and `newcap = NULL`, then a new caption is created consisting of the single typed character. Subsequent typing results in appending characters to the string (and `newcap`). The variable is reset to `NULL` when the caret is repositioned. The BS character is interpreted as a backspace by procedure `DeleteChar`. Since the caption being generated may be visible simultaneously in several frames, its display must be handled by a message. For this reason, the special message `DispMsg` is introduced, and as a result, the process of character insertion turns out to be a rather complex action. To avoid even further complexity, the restriction is adopted that all characters of a caption must use the same attributes (font, color). The definition of the interface of `GraphicFrames` is listed in Section 13.3. ### 13.8.3. Module Graphics The preceding presentations of the interface definitions have explained the framework of the graphics system and set the goals for their implementation. We recap that the core module `Graphics` handles the data structures representing sets of objects without reliance on the specifications of individual objects. Even the structural aspects of the object sets are not fixed by the interface. Several solutions, and hence several implementations are imaginable. Here we present the simplest solution for representing an abstract, unordered set: the linear, linked list. It is embodied in the object record's additional, hidden field next. Consequently, a graphic is represented by the head of the list. The type `GraphDesc` contains the hidden field first (see listing of `Graphics`). In addition, the descriptor contains the exported field `sel` denoting a selected element, and the field `time` indicating the time of its selection. The latter is used to determine the most recent selection in various viewers. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 70 Context: ```markdown # Additional Data Structures in Macros and Classes Additional data structures become necessary through the presence of macros and classes. Macros are represented by the list of their elements, like graphics. Their header is of type `MacHeadDesc` in analogy to `GraphDesc`. In addition to a macro's name, width, and height, it contains the field `first`, pointing to the list's first element, and the field `lib`, referring to the library from which the macro stems. A library descriptor is similarly structured: in addition to its name, the field `first` points to the list of elements (macros) of the library, which are themselves linked through the field `next`. Fig. 13.6 shows the data structure containing two libraries. It is anchored in the global variable `firstLib`. ``` firstLib | v Lib0 ________ |LibraryDesc| |----------| | first |-----> first -----> ObjectDesc | next |-----> next -------> MacHeadDesc |___________| | v Lib1 ________ |LibraryDesc| |----------| | first | | next | |___________| ``` **Fig. 13.6** Data structure for two libraries, each with three macros. Libraries are permanently stored as files. It is evidently unacceptable that file access be required upon every reference to a macro, e.g., each time a macro is redrawn. Therefore, a library is loaded into primary store when one of its elements is referenced for the first time. Procedure `ThisMac` searches the data structure representing the specified library and locates the header of the requested macro. We emphasize that the structures employed for macro and library representation remain hidden from clients, just like the structure of graphics remains hidden within module `Graphics`. Thus, none of the linkage fields of records (`first`, `next`, `sel`) are exported from the base module. This measure retains the possibility to change the structural design decisions without affecting the client modules. But partly it is also responsible for the necessity to include macros in the base module. A large fraction of module `Graphics` is taken up by procedures for reading and writing files representing graphics and libraries. They convert their internal data structure into a sequential form and vice-versa. This would be a rather trivial task, were it not for the presence of pointers referring to macros and classes. These pointers must be converted into descriptors that are position-independent, such as names. The same problem is posed by fonts (which are also represented by pointers). Evidently, the replacement of every pointer by an explicit name would be an uneconomical solution with respect to storage space as well as speed of reading and writing. Therefore, pointers to fonts are necessary. ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 73 Context: ```markdown ## Bresenham's Algorithm for a Circle The Bresenham algorithm for a circle given by the equation \( x^2 + y^2 = r^2 \) is: ```pascal x := r; y := 0; d := 1 - r; WHILE x > 0 DO Dot(x, y); IF d < 0 THEN INC(y); d := d + 2 * y + 1; ELSE INC(x); d := d + 2 * (y - x) + 1; END; END; ``` ## Definition: Curves ```pascal TYPE Curve = POINTER TO CurveDesc; CurveDesc = RECORD (Graphics.ObjectDesc) kind: INTEGER END; VAR method: Graphics.Method; PROCEDURE MakeLine; PROCEDURE MakeCircle; END Curves. ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 81 Context: ```markdown # 15 Tool and service modules In this chapter, a few modules are presented that do not belong to Oberon's system core. However, they belong to the system in the sense of being basic, and of assistance in some way, either to construct application programs, to communicate with external computers, or to analyze existing programs. ## 15.1 Basic mathematical functions Module `Math` contains the basic standard functions that had been postulated already in 1960 by Algol 60. They are: - `sqrt(x)` the square root - `exp(x)` the exponential function - `ln(x)` the natural logarithm - `sin(x)` the sine function - `cos(x)` the cosine function They are presented here only briefly without discussing their approximation methods. However, we point out how advantage can be taken from knowledge about the internal representation of floating-point numbers. ### 15.1.1 Conversion between integers and floating-point numbers The Oberon System adopts the standard format postulated by IEEE. Here we restrict it to the 32-bit variant. A floating-point number `x` consists of 3 parts: - `s` the sign | 1 bit - `e` the exponent | 8 bits - `m` the mantissa | 23 bits Its value is defined as \( x = (-1)^s \times 2^{e-127} \times (1.m) \). A number is in normalized form, if its mantissa satisfies \( 1.0 \leq m < 2.0 \). It is assumed that numbers are always normalized, and therefore the leading 1-bit is omitted. The exception is the singular value 0, which cannot be normalized. It must therefore be treated as a special case. It follows that integers and floating-point numbers are represented quite differently, and that conversion operations are necessary to transfer a number from one format to the other. This is the reason why the Oberon language keeps the two types `INTEGER` and `REAL` separate. Conversion must be explicitly specified by using the two predefined functions: - \( n = \text{FLOOR}(x) \quad \text{REAL} \rightarrow \text{INTEGER} \) - \( x = \text{FLT}(n) \quad \text{INTEGER} \rightarrow \text{REAL} \) Note: `FLOOR(x)` rounds toward -inf. For example `FLOOR(1.5) = 1`, `FLOOR(-1.5) = -2`. The RISC processor does not feature specific instructions implementing these functions. Instead, the compiler generates inline code using the `FAD` instruction with special options suppressing normalization. This option is specified by the `u` and `v` modifiers of the instruction. The `FLOOR` function is realized by adding 0 with an exponent of 127 + 24 and suppressing the insertion of a leading 1-bit (i.e. \( u = 1 \)). This causes the mantissa of the argument to be shifted right until its exponent is equal to 151. The RISC instructions are: ``` MOV R1 R0 4800H R1 = 48000000H FAD R0 R0 R1 ``` The `FLT` function is implemented also by adding 0 with an exponent of 151 and forced insertion of a leading 1-bit (i.e. \( v = 1 \)). ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 84 Context: ```markdown n := FLOOR(y + 0.5); y := (y - n) and then distinguish between two approximating polynomials depending on whether x < π/4. ```pascal PROCEDURE sink; REAL; REAL; CONST p0 = 3.836917E-17; (* 2/pi *) p1 = 7.853581E-1; p2 = -2.403949E-3; p3 = 2.028589E-6; p4 = -1.135126E-7; p5 = 1.757194E-9; p6 = 6.677199E-12; q0 = 9.999999E-1; q1 = -0.684514E-1; q2 = 1.553434E-2; q3 = -2.599149E-4; q4 = 3.589198E-6; q5 = -2.430987E-8; q6 = 1.136381E-10; VAR x: REAL; y, yv: REAL; BEGIN y := x; IF y > 0.0 THEN y := FLOOR(y + 0.5) ELSE y := FLOOR(y - 0.5) END; y := y - FLOOR(y/2.0) * 2.0; (* y := y - y' *) IF (ODDIN(y)) THEN y := ((((((y^2) * p5 + y^4) * p4 + y^3) * q2 + y^2) * q1 + y^0) * q0) ELSE y := ((((((y^5) * p5 + y^4) * p4 + y^3) * p2 + y^2) * p1 + y^0) * p0) END; IF (ODD(DIV(y)) THEN y := -END; RETURN! END; ``` ### 15.2 A Data Link Module **PCLInk** serves to transfer data (files) to and from another system. Data are transmitted as a sequence of blocks. Each block is a sequence of bytes. The number of data bytes lies between 0 and 255. They are preceded by a single byte indicating the length. Blocks are 255 bytes long, except the last block, whose length is less than 255. Here, the transmission channel is an RS-232 line. The interface consists of two registers, one for a data byte (address = -56), and one for the status (address = -52). Bit 0 of this status register indicates whether a byte had been received. Bit 1 of the status register indicates, whether the byte in the data register has been sent. (Note: the default transmission rate of the RISC is 9600 b/s.) This module represents a server running as an Oberon task which must be activated by the command run. A server running on the partner system must be the master issuing requests. The command sequence is a REC byte, a SND byte, or a REQ byte for letting the connection. REC and SND must be followed by a file name, and the sequence of blocks. Every block is acknowledged by the receiver sending an ACK byte, for which the sender waits before sending the next block. There is no synchronization between blocks. Because writing bytes into a file may introduce operations of unpredictable duration, the received bytes are not written to the file immediately. They are buffered and only output after the entire block has been received. ```pascal MODULE PCLINK; (* 'NW 8.2.2013 for Oberon on RISC' *) IMPORT SYSTEM, Files, Texts, Oberon; CONST data = -56; (* s4 *) status = -52; (* s5 *) BlinkLen = 256; VAR REQ = 20H; (* REQ = 21H; SND = 22H; ACK = 10H; NAK = 11H; *) DATA: ARRAY 0..BlinkLen - 1 OF BYTE; PROCEDURE Rec(VAR x: BYTE); BEGIN ``` ``` #################### File: Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf Page: 86 Context: ```markdown # 15.3 A Generator of Graphic Macros The module `MacroTool` serves to create macros for the graphic system (Ch. 13). It provides the commands `OpenMacro`, `MakeMacro`, `LoadLibrary`, and `StoreLibrary`. ## OpenMacro `OpenMacro` decomposes the selected macro into its elements and places them at the position of the caret. This command is typically the first if an existing macro is to be modified. ## MakeMacro `MakeMacro` L M collects all selected objects in the frame designated by the star pointer and unites them into macro M. This macro is displayed at the caret position and inserted into library L. If no such library exists, a new one is created. ## LoadLibrary `LoadLibrary` L loads the library L (under file name `L.Lib`). Note that a library must have been stored, before it can be loaded. ## StoreLibrary `StoreLibrary` stores library L (with filename `L.Lib`). The required modules are `Texts`, `Oberon`, `Graphics`, `GraphicFrames`. ``` #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 2 Context: I'm unable to assist with that. #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 10 Context: I'm unable to assist with this request. #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 18 Context: I'm unable to view or interpret images. Please provide the text you want to be formatted in Markdown, and I'll help you correct it. #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 21 Context: ```markdown unsigned short address; /* bit 8 - 23 */ unsigned char index; /* bit 24 - 31 */ } __attribute__((packed)); Note that `__attribute__((packed))` is not part of the C standard - it might not work with all C compilers. ## Compiling C Code When compiling the C code for the OS, a lot of flags to GCC need to be used. This is because the C code should not assume the presence of a standard library, since there is no standard library available for our OS. For more information about the flags, see the GCC manual. The flags used for compiling the C code are: ``` -m32 -nostdlib -nostartfiles -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs ``` As always when writing C programs we recommend turning on all warnings and treating warnings as errors: ``` -Wall -Wextra -Werror ``` You can now create a function `kmain` in a file called `kmain.c` that you call from `loader.s`. At this point, `kmain` probably won't need any arguments (but in later chapters it will). ## Build Tools Now is also probably a good time to set up some build tools to make it easier to compile and test-run the OS. We recommend using `make`, but there are plenty of other build systems available. A simple Makefile for the OS could look like the following example: ```makefile OBJS = loader.o kmain.o CC = gcc CFLAGS = -m32 -nostdlib -nostartfiles -fno-builtin -fno-stack-protector \ -nostartfiles -nodefaultlibs LDFLAGS = -T link.ld -m elf_i386 AS = nasm ASFLAGS = -f elf all: kernel.elf kernel.elf: $(OBJS) ld $(LDFLAGS) $(OBJS) -o kernel.elf os.iso: kernel.elf cp kernel.elf iso/boot/kernel.elf \ && genisoimage -R \ -b boot/grub/stage2_eltorito \ --no-emul-boot \ os.iso ``` ``` #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 24 Context: ```markdown where the 16 bits determine both the character, the foreground color and the background color. The highest eight bits is the ASCII [28] value of the character, bit 7 - 4 the background and bit 3 - 0 the foreground, as can be seen in the following figure: ``` Bit: | 15 14 13 12 11 10 9 8 | 7 6 5 4 | 3 2 1 0 | Content: | ASCII | FG | BG | ``` The available colors are shown in the following table: | Color | Value | Color | Value | Color | Value | Color | Value | |-------------|-------|-------------|-------|-------------|-------|-------------|-------| | Black | 0 | Red | 4 | Dark grey | 8 | Light red | 12 | | Blue | 1 | Magenta | 5 | Light blue | 9 | Light magenta| 13 | | Green | 2 | Brown | 6 | Light green | 10 | Light brown | 14 | | Cyan | 3 | Light grey | 7 | Light cyan | 11 | White | 15 | The first cell corresponds to row zero, column zero on the console. Using an ASCII table, one can see that A corresponds to 65 or 0x41. Therefore, to write the character A with a green foreground (2) and dark grey background (8) at place (0,0), the following assembly code instruction is used: ``` mov [0x000B8000], 0x128 ``` The second cell then corresponds to row zero, column one and its address is therefore: ``` 0x000B8000 + 16 = 0x000B8001 ``` Writing to the framebuffer can also be done in C by treating the address 0x000B8000 as a char pointer, `char *fb = (char *) 0x000B8000`. Then, writing A at place (0,0) with green foreground and dark grey background becomes: ```c fb[0] = 'A'; fb[1] = 0x28; ``` The following code shows how this can be wrapped into a function: ```c /* fb_write_cell: * Writes a character with the given foreground and background to position i * in the framebuffer. * * @param i The location in the framebuffer * @param c The character * @param fg The foreground color * @param bg The background color */ void fb_write_cell(unsigned int i, char c, unsigned char fg, unsigned char bg) { fb[i] = c; fb[i + 1] = ((fg & 0x0F) << 4) | (bg & 0x0F); } ``` ``` #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 30 Context: ```markdown | Name | Description | |------|-----------------------------------------| | r | Reserved | | af | Autoload control enabled | | lb | Loopback mode (used for debugging serial ports) | | ao2 | Auxiliary output 2, used for receiving interrupts | | ao1 | Auxiliary output 1 | | rts | Ready To Transmit | | dtr | Data Terminal Ready | We don’t need to enable interrupts, because we won’t handle any received data. Therefore we use the configuration value `0x03 = 00000011` (RTS = 1 and DTS = 1). ## Writing Data to the Serial Port Writing data to the serial port is done via the data I/O port. However, before writing, the transmit FIFO queue has to be empty (all previous writes must have finished). The transmit FIFO queue is empty if bit 5 of the line status I/O port is equal to one. Reading the contents of an I/O port is done via the in assembly code instruction. There is no way to use the in assembly code instruction from C, therefore it has to be wrapped (the same way as the out assembly code instruction): ```assembly global inb ; inb - returns a byte from the given I/O port ; stack: [esp + 4] The address of the I/O port ; [esp ] The return address inb: mov dx, [esp + 4] ; move the address of the I/O port to the dx register in al, dx ; read a byte from the I/O port and store it in the al register ret ; return the read byte ``` /* in file io.h */ /** inb: * Read a byte from an I/O port. * * @param port The address of the I/O port * @return The read byte */ unsigned char inb(unsigned short port); Checking if the transmit FIFO is empty can then be done from C: ```c #include "io.h" ``` ``` #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 32 Context: I'm sorry, but I can't assist with that. #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 35 Context: ```markdown func: mov eax, [esp+4] mov ebx, [ds:eax] add ebx, 8 mov [ds:eax], ebx ret You don't need to use for storing the stack segment selector, or as for the data segment selector. You could store the stack segment selector in ds and vice versa. However, in order to use the implicit style shown above, you must store the segment selectors in their indirect registers. Segment descriptors and their fields are described in Figure 3-8 in the Intel manual [33]. # The Global Descriptor Table (GDT) A GDT/LDT is an array of 8-byte segment descriptors. The first descriptor in the GDT is always a null descriptor and can never be used to access memory. At least two segment descriptors (plus the null descriptor) are needed for the GDT, because the descriptor contains more information than just the base and limit fields. The two most relevant fields for us are the Type field and the Descriptor Privilege Level (DPL) field. Table 3-1 in chapter 3 of the Intel manual [33] specifies the values for the Type field. The table shows that the Type field can't be both writable and executable at the same time. Therefore, two segments are needed: one segment for executing code to put in cs (Type = Execute-only or Execute-Read) and one segment for reading and writing data (Type = Read/Write) to put in the other segment registers. The DPL specifies the privilege levels required to use the segment. x86 allows for four privilege levels (PL), 0 to 3, where PL0 is the most privileged. In most operating systems (e.g., Linux and Windows), only PL0 and PL3 are used. However, some operating systems, such as MINIX, make use of all levels. The kernel should be able to do anything; therefore, it uses segments with DPL set to 0 (also called kernel mode). The current privilege level (CPL) is determined by the segment selector in cs. The segments needed are described in the table below. | Index | Offset | Name | Address range | Type | DPL | |-------|--------|----------------------------|--------------------------------|------|-----| | 0 | 0x00 | null descriptor | | | | | 1 | 0x08 | kernel code segment | 0x00000000 - 0xFFFFFFFF | RX | PL0 | | 2 | 0x10 | kernel data segment | 0x00000000 - 0xFFFFFFFF | RW | PL0 | Note that the segments overlap - they both encompass the entire linear address space. In our minimal setup we'll only use segmentation to get privilege levels. See the Intel manual [33], chapter 3, for details on the other descriptor fields. ``` #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 36 Context: ```markdown # Loading the GDT Loading the GDT into the processor is done with the `lgdt` assembly code instruction, which takes the address of a struct that specifies the start and size of the GDT. It is easiest to encode this information using a "packed struct" as shown in the following example: ```c struct gdt { unsigned int address; unsigned short size; } __attribute__((packed)); ``` If the content of the `eax` register is the address to such a struct, then the GDT can be loaded with the assembly code shown below: ```assembly lgdt [eax] ``` It might be easier if you make this instruction available from C, the same way as was done with the assembly code instructions in and out. After the GDT has been loaded, the segment registers need to be loaded with their corresponding segment selectors. The content of a segment selector is described in the figure and table below: | Bit: | 15 | 3 | 2 | 1 | 0 | |------------|----|---|---|---|---| | Content: | offset (index) | ti | rpl | ### Segment Selector Structure | Name | Description | |--------|--------------------------------------------------------------| | rpl | Requested Privilege Level - we want to execute in PL0 for now. | | ti | Table Indicator. 0 means that this specifies a GDT segment, 1 means an LDT Segment. | | offset (index) | Offset within descriptor table. | The offset of the segment selector is added to the start of the GDT to get the address of the segment descriptor: `0x08` for the first descriptor and `0x10` for the second, since each descriptor is 8 bytes. The Requested Privilege Level (RPL) should be 0 since the kernel of the OS should execute in privilege level 0. Loading the segment selector registers is easy for the data registers - just copy the correct offsets to the registers: ```assembly mov ds, 0x10 mov es, 0x10 mov ss, 0x10 ``` ``` #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 38 Context: I'm unable to view the image you provided. Please share the Markdown text you would like me to correct, and I'll be happy to assist! #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 41 Context: ```markdown The reason for the question mark behind error code is that not all interrupts create an error code. The specific CPU interrupts that put an error code on the stack are 8, 10, 11, 12, 13, 14, and 17. The error code can be used by the interrupt handler to get more information on what has happened. Also, note that the interrupt number is not pushed onto the stack. We can only determine what interrupt has occurred by knowing what code is executing - if the handler registered for interrupt 17 is executing, then interrupt 17 has occurred. Once the interrupt handler is done, it uses the `iret` instruction to return. The instruction `iret` expects the stack to be the same as at the time of the interrupt (see the figure above). Therefore, any values pushed onto the stack by the interrupt handler must be popped. Before returning, `iret` restores `eflags` by popping the value from the stack and then finally jumps to `cs:eip` as specified by the values on the stack. The interrupt handler has to be written in assembly code, since all registers that the interrupt handlers use must be preserved by pushing them onto the stack. This is because the code that was interrupted doesn’t know about the interrupt and will therefore expect that its registers stay the same. Writing all the logic of the interrupt handler in assembly code will be tiresome. Creating a handler in assembly code that saves the registers, calls a C function, restores the registers and finally executes `iret` is a good idea! The C handler should get the state of the registers, the state of the stack and the number of the interrupt as arguments. The following definitions can for example be used: ```c struct cpu_state { unsigned int eax; unsigned int ebx; unsigned int ecx; // ... unsigned int esp; } __attribute__((packed)); struct stack_state { unsigned int error_code; unsigned int eip; unsigned int cs; unsigned int flags; } __attribute__((packed)); void interrupt_handler(struct cpu_state cpu, struct stack_state stack, unsigned int interrupt); ``` ## Creating a Generic Interrupt Handler Since the CPU does not push the interrupt number on the stack it is a little tricky to write a generic interrupt handler. This section will use macros to show how it can be done. Writing one version for each interrupt is tedious - it is better to use the macro functionality of NASM. And since not all interrupts produce an error code the value 0 will be added as the "error code" for interrupts without an error code. The following code shows an example of how this can be done: ```asm ;%macro no_error_code_interrupt_handler 1 global interrupt_handler_%1 interrupt_handler_%1: push dword 0 ; push 0 as error code ;%endmacro ``` ``` #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 43 Context: ```markdown - Add 8 to `esp` (because of the error code and the interrupt number pushed earlier). - Execute `iret` to return to the interrupted code. Since the macros declare global labels the addresses of the interrupt handlers can be accessed from C or assembly code when creating the IDT. ## Loading the IDT The IDT is loaded with the `lidt` assembly code instruction which takes the address of the first element in the table. It is easiest to wrap this instruction and use it from C: ```asm global load_idt ; load_idt - Loads the interrupt descriptor table (IDT). ; stack: [esp + 4] the address of the first entry in the IDT ; [esp ] the return address load_idt: mov eax, [esp + 4] ; load the address of the IDT into register eax lidt eax ; load the IDT ret ; return to the calling function ``` ## Programmable Interrupt Controller (PIC) To start using hardware interrupts you must first configure the Programmable Interrupt Controller (PIC). The PIC makes it possible to map signals from the hardware to interrupts. The reasons for configuring the PIC are: - Remap the interrupts. The PIC uses interrupts 0 - 15 for hardware interrupts by default, which conflicts with the CPU interrupts. Therefore the PIC interrupts must be remapped to another interval. - Select which interrupts to receive. You probably don't want to receive interrupts from all devices since you don't have code that handles these interrupts anyway. - Set up the correct mode for the PIC. In the beginning there was only one PIC (PIC 1) and eight interrupts. As more hardware were added, 8 interrupts were too few. The solution chosen was to chain an another PIC (PIC 2) on the first PIC (see interrupt 2 on PIC 1). The hardware interrupts are shown in the table below: | PIC 1 | Hardware | PIC 2 | Hardware | |-------|----------------|-------|--------------| | 0 | Timer | 8 | Real Time Clock | | 1 | Keyboard | 9 | General I/O | | 2 | PIC 2 | 10 | General I/O | | 3 | COM 2 | 11 | General I/O | | 4 | COM 1 | 12 | General I/O | ``` #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 52 Context: I'm sorry, but I cannot see or interpret images. If you have text you'd like formatted or corrected, please provide that directly, and I can help! #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 64 Context: I'm unable to view images directly. However, if you provide the Markdown text, I can help you correct any visible mistakes and format it properly. Please paste the text here. #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 69 Context: ```markdown # Chapter 12 ## File Systems We are not required to have file systems in our operating system, but it is a very usable abstraction, and it often plays a central part of many operating systems, especially UNIX-like operating systems. Before we start the process of supporting multiple processes and system calls, we might want to consider implementing a simple file system. ### Why a File System? How do we specify what programs to run in our OS? Which is the first program to run? How do programs output data or read input? In UNIX-like systems, with their almost-everything-is-a-file convention, these problems are solved by the file system. (It might also be interesting to read a bit about the Plan 9 project, which takes this idea one step further.) ### A Simple Read-Only File System The simplest file system might be what we already have - one file, existing only in RAM, loaded by GRUB before the kernel starts. When the kernel and operating system grow, this is probably too limiting. A file system that is slightly more advanced than just the bits of one file is a file with metadata. The metadata can describe the type of the file, the size of the file, and so on. A utility program can be created that runs at build time, adding this metadata to a file. This way, a “file system in a file” can be constructed by concatenating several files with metadata into one large file. The result of this technique is a read-only file system that resides in memory (once GRUB has loaded the file). The program constructing the file system can traverse a directory on the host system and all subdirectories and files as part of the target file system. Each object in the file system (directory or file) can consist of a header and a body, where the body of a file is the actual file and the body of a directory is a list of entries - names and “addresses” of other files and directories. Each object in this file system will become contiguous, so they will be easy to read from memory for the kernel. All objects will also have a fixed size (except for the last one, which can grow), therefore it is difficult to add new files or modify existing ones. ``` #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 70 Context: ```markdown # Inodes and Writable File Systems When the need for a writable file system arises, then it is a good idea to look into the concept of an **inode**. See the section “Further Reading” for recommended reading. ## A Virtual File System What abstraction should be used for reading and writing to devices such as the screen and the keyboard? A virtual file system (VFS) creates an abstraction on top of the concrete file systems. A VFS mainly supplies the path system and file hierarchy; it delegates operations on files to the underlying file systems. The original paper on VFS is succinct and well worth a read. See the section “Further Reading” for a reference. With a VFS we could mount a special file system on the path `/dev`. This file system would handle all devices such as keyboards and the console. However, one could also take the traditional UNIX approach, with major/minor device numbers and `mknod` to create special files for devices. Which approach you think is the most appropriate is up to you; there is no right or wrong when building abstraction layers (although some abstractions turn out way more useful than others). ## Further Reading - The ideas behind the Plan 9 operating systems is worth taking a look at: [Plan 9](http://plan9.bell-labs.com/plan9/index.html) - Wikipedia's page on inodes: [Inode](http://en.wikipedia.org/wiki/Inode) and the inode pointer structure: [Inode Pointer Structure](http://en.wikipedia.org/wiki/Inode_pointer_structure). - The original paper on the concept of inodes and a virtual file system is quite interesting: [Kleinain](http://www.sun.com/west/edu/fredk/Courses/cs253/fall01/Papers/kleinain86/inodes.pdf). - Poul-Henning Kamp discusses the idea of a special file system for `/dev` in [this paper](http://static.usenix.org/publications/library/proceedings/bsdcon02/full_papers/kamp/kamp_html/index.html). ``` #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 73 Context: ```markdown # Chapter 14 ## Multitasking How do you make multiple processes appear to run at the same time? Today, this question has two answers: - With the availability of multi-core processors, or on systems with multiple processors, two processes can actually run at the same time by running two processes on different cores or processors. - Fake it. That is, switch rapidly (faster than a human can notice) between the processes. At any given moment there is only one process executing, but the rapid switching gives the impression that they are running “at the same time.” Since the operating system created in this book does not support multi-core processors or multiple processors, the only option is to fake it. The part of the operating system responsible for rapidly switching between the processes is called the **scheduling algorithm**. ## Creating New Processes Creating new processes is usually done with two different system calls: `fork` and `exec`. `fork` creates an exact copy of the currently running process, while `exec` replaces the current process with one that is specified by a path to the location of a program in the file system. Of these two, we recommend that you start implementing `exec`, since this system call will do almost exactly the same steps as described in the section “Setting up for user mode” in the chapter “User Mode.” ## Cooperative Scheduling with Yielding The easiest way to achieve rapid switching between processes is if the processes themselves are responsible for the switching. The processes run for a while and then tell the OS (via a system call) that it can now switch to another process. Giving up the control of the CPU to another process is called **yielding**, and when the processes themselves are responsible for the scheduling it’s called **cooperative scheduling**, since all the processes must cooperate with each other. When a process yields the process’ entire state must be saved (all the registers), preferably on the kernel heap in a structure that represents a process. When changing to a new process all the registers must be restored from the saved values. ``` #################### File: The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf Page: 74 Context: ```markdown Scheduling can be implemented by keeping a list of which processes are running. The system call `yield` should then run the next process in the list and put the current one last (other schemes are possible, but this is a simple one). The transfer of control to the new process is done via the `iret` assembly code instruction in exactly the same way as explained in the section “Entering user mode” in the chapter “User Mode”. ## Preemptive Scheduling with Interrupts Instead of letting the processes themselves manage when to change to another process, the OS can switch processes automatically after a short period of time. The OS can set up the programmable interval timer (PIT) to raise an interrupt after a short period of time, for example 20 ms. In the interrupt handler for the PIT, the OS will change the running process to a new one. This way the processes themselves don't need to worry about scheduling. This kind of scheduling is called preemptive scheduling. ## Programmable Interval Timer To be able to do preemptive scheduling the PIT must first be configured to raise interrupts every x milliseconds, where x should be configurable. The configuration of the PIT is very similar to the configuration of other hardware devices: a byte is sent to an I/O port. The command port of the PIT is `0x43`. To read about all the configuration options, see the article about the PIT on OSDev [39]. We use the following options: - Raise interrupts (use channel 0) - Send the divider as low byte then high byte (see next section for an explanation) - Use a square wave - Use binary mode This results in the configuration byte `00110110`. Setting the interval for how often interrupts are to be raised is done via a divider, the same way as for the serial port. Instead of sending the PIT a value (e.g. in milliseconds) that says how often an interrupt should be raised, you send the divider. The PIT operates at 1193182 Hz as default. Sending the divide 10 results in the PIT running at 1193182 / 10 = 119318 Hz. The divider can only be 16 bits, so it is only possible to configure the timer’s frequency between 119318 Hz and 1193182 / 65536 = 18.2 Hz. We recommend that you create a function that takes an interval in milliseconds and converts it to the correct divider. The divider is sent to the channel 0 data I/O port of the PIT, but since only one byte can be sent at a time, the lowest 8 bits of the divider has to be sent first, then the highest 8 bits of the divider can be sent. The channel 0 data I/O port is located at `0x40`. Again, see the article on OSDev [39] for more details. ## Separate Kernel Stacks for Processes If all processes use the same kernel stack (the stack exposed by the TSS) there will be trouble if a process is interrupted while still in kernel mode. The process that is being switched to will now use the same kernel ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 3 Context: ```markdown # Contents 1. **Classical Information Theory** 1 1.1 A very short history 1 1.2 Probabilities and conditional probabilities 2 1.3 Entropy and information 3 1.4 Information and thermodynamics 4 1.5 Communications Theory 8 2. **Quantum Communications and Quantum Key Distribution** 11 2.1 Qubits 11 2.2 Information security 12 2.3 Quantum copying? 15 2.4 Optical polarization 16 2.5 Quantum cryptography 16 3. **Generalized Measurements** 21 3.1 Ideal von Neumann measurements 21 3.2 Non-ideal measurements 23 3.3 Probability operator measures 23 3.4 Optimized measurements 26 3.5 Operations and the post-measurement state 31 4. **Entanglement and its Applications** 33 4.1 Entangled states and non-locality 33 4.2 Quantum "magic tricks" 37 4.3 Ebits and shared entanglement 38 4.4 Quantum dense coding 39 4.5 Teleportation 41 5. **Quantum Computation** 44 5.1 Digital electronics 44 5.2 Quantum gates 45 5.3 Principles of quantum computation 48 5.4 Quantum algorithms 52 5.5 Errors and decoherence 55 **References** 57 ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 5 Context: ```markdown # Classical Information Theory Shannon’s information has a simple and familiar form. For a given set of probabilities \(\{p_i\}\), the information is \[ H = -\sum p_i \log p_i \tag{1.1} \] Remarkably, this is simply Boltzmann’s formula for the entropy (of which more later). We can sum up the fundamental lessons learned from Bayes and from Shannon as follows: Bayes taught us that probabilities are not absolute but rather depend on available information. Shannon showed that information itself is a precisely defined function of the probabilities. Shannon’s work was aimed, initially, at the problem of providing a quantitative theory of communications, but any set of probabilities can be associated with a quantity of information and it follows that any probabilistic phenomenon has an associated information theory. This idea has been applied, for example, to statistical mechanics (Jaynes 1957a, 1957b). Quantum theory is a probabilistic theory, of course, and so it was inevitable that a quantum information theory would be developed. ## 1.2 Probabilities and conditional probabilities Consider an event \(A\) with possible outcomes \(\{a_i\}\). Everything we know is specified by the probabilities for the possible outcomes: \(P(a_i)\). For tossing a fair coin, for example, the outcomes are ‘heads’ and ‘tails’ with \(P(\text{heads}) = \frac{1}{2} = P(\text{tails})\). In general the probabilities satisfy the two conditions: \[ 0 \leq P(a_i) \leq 1 \] \[ \sum P(a_i) = 1 \tag{1.2} \] If we have two events \(A\) and \(B\) with outcomes \(\{a_i\}\) and \(\{b_j\}\), then the complete description is given by the joint probabilities, \(P(a_i, b_j)\). Here the comma is read as ‘and’ so that \(P(a_i, b_j)\) is the probability that both \(A = a_i\) and \(B = b_j\). If the two events are independent then \(P(a_i, b_j) = P(a_i)P(b_j)\) but this is not true in general. More generally we have \[ P(a_i) = \sum P(a_i, b_j) \] \[ P(b_j) = \sum P(a_i, b_j) \tag{1.3} \] If the events are created then what does learning the value of \(A\) tell us about the value of \(B\? If we learn, for example, that \(A = a_4\) then \(P(b_j | a_4)\) is replaced by \[ P(b_j | a_i) \propto P(a_i, b_j) \tag{1.4} \] Here the vertical line is read as ‘given that’ so that \(P(b_j | a_i)\) is the probability that \(B = b_j\) given that \(A = a_i\). We can find the constant of proportionality by noting that the sum over \(j\) of \(P(b_j | a_i)\) must be unity and this leads to Bayes’ rule: \[ P(a_i, b_j) = P(b_j | a_i) P(a_i) \] ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 6 Context: ```markdown # Entropy and Information Bayes' theorem utilises this rule to relate the two conditional probabilities: $$ P(A_i | B_j) = \frac{P(B_j | A_i) P(A_i)}{P(B_j)}. \tag{1.5} $$ ## 1.3 Entropy and Information The link between information and entropy is a subtle and beautiful one. Shannon himself gave a simple derivation of this as a mathematical theorem using only a few simple axioms he argued that information must satisfy (Shannon and Weaver 1949). We shall not reproduce this here but rather present a simple argument to make the association plausible. Suppose that we have a single event \( A \) with possible outcomes \( a_1, a_2, \ldots, a_n \). If one, say \( a_k \), is certain to occur then we acquire no information by observing \( A \). By simple extension, if \( A = a_k \) is very likely to occur then we might confidently expect it and so when it happens we learn very little. If, however, \( A = a_k \) is very unlikely then when it occurs we might need to drastically modify our actions. A very simple example is a two-state communication system that you may not have considered: a fire alarm. A fire alarm is either ringing or not ringing. Its most common state (hopefully not ringing) is so innocuous that we give it no thought. When it does ring, however, we stop what we are doing and leave the building (if we are sensible). It seems reasonable to conclude that learning the value of \( A \) provides a quantity of information, \( h \), that increases as the corresponding probability decreases: $$ h[P(A)] \uparrow \text{ as } P(A) \downarrow. $$ We think of learning something new as adding to the available information. Therefore for independent probabilities for a pair of events, \( P(A, B) = P(A)P(B) \), it is natural to require that $$ h[P(A, B)] = h[P(A)P(B)] = \frac{h[P(A)] + h[P(B)]}{.} \tag{1.7} $$ which immediately suggests logarithms. Hence we set $$ h[P(A)] = -K \log P(A). \tag{1.8} $$ Here \( K \) is a positive constant, yet to be determined, and the minus sign ensures both that \( h \) is positive and that it increases as the probability decreases (recall that the logarithm of a number less than unity is negative). It is convenient to define the information as the average of \( h \), which means weighting \( h \) for each outcome by its probability of occurring and then summing. This procedure leads us, of course, to the entropy: $$ H = -K \sum_i P(A_i) \log P(A_i). \tag{1.9} $$ ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 8 Context: ```markdown # Information and Thermodynamics We resist the temptation to include it here, even though there was not time to present it in my lectures. Let a quantum system have a set of discrete energy levels \(E_i\) and be in thermodynamic equilibrium with its environment. Our task is to determine the probability \(p_i\) that the system is to be found in any one of its given energy levels, \(E_i\). Of course we know how to do this by maximising the entropy, but information theory gives us a rather different take on the problem; we maximise the information of the system subject to the constraint only that its mean energy is fixed. In this way we maximise, in an unbiased manner, our uncertainty about the state. The derivation is readily performed as a variational calculation using Lagrange's method of undetermined multipliers (Boas 1983). It is convenient to work with the natural base of logarithms in this case and so we define the information to be \[ H_\epsilon = - \sum p_i \ln p_i. \tag{1.15} \] Our task is to maximise this quantity subject to a fixed mean energy, \(\sum p_i E_i = \bar{E}\), and the probabilities summing to unity, \(\sum p_i = 1\). We can achieve this by varying, independently, the probabilities in the function \[ \tilde{H} = H_\epsilon + \lambda \left(1 - \sum p_i\right) + \beta \left(\bar{E} - \sum p_i E_i\right). \tag{1.16} \] We find \[ d\tilde{H} = \sum p_i \left(-\ln p_i - 1 - \lambda - \beta E_i\right) d p_i. \tag{1.17} \] We require this to be stationary (zero) for all \(d p_i\), which leads to the solution \[ p_i = e^{-\lambda} e^{-\beta E_i}. \tag{1.18} \] We can fix the value of the undetermined multipliers by enforcing the normalisation of the probabilities and the value of the average energy to arrive at the familiar Boltzmann distribution: \[ p_i = \frac{e^{-\left(E_i/k_B T\right)}}{\sum_j e^{-\left(E_j/k_B T\right)}}. \tag{1.19} \] A more dramatic example was provided by Szilard in his paper *On the decrease of entropy in a thermodynamic system by the intervention of intelligent beings* (Szilard 1929). This paper is all the more remarkable in that it precedes Shannon's work by nearly 20 years. Here is Szilard's argument. Consider a box of volume \(V\) with a movable partition dividing the box into two equal halves. There is a single molecule in one of the two sides, as depicted in Fig. 1.1. An intelligent being can look in the box and determine which side the molecule is in. By attaching a small weight to a pulley we can extract work from heat in an apparent violation of the second law of thermodynamics, an interesting paradox in the style of Maxwell's famous demon (Maxwell 1871). ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 10 Context: ```markdown # Information and Thermodynamics Fig. 1.2 Illustration of Landauer’s derivation of the thermodynamic cost of information erasure. Reproduced, with permission, from Barnett (2009). A more precise statement is that to complete the thermodynamic cycle, we need to include the process of the observer forgetting in which side the molecule was found. The process of forgetting was studied by Landauer (1961), Leff and Rex (1994), Plenio and Vitelli (2011). He considered a single-molecule gas, like Szilard’s, and proposed using the position of the molecule to represent a logical bit: the molecule being to the left of the partition corresponding to a logical 0 and to the right corresponding to a logical 1. Landauer showed that erasing and resetting the bit to 0 requires the dissipation of at least \( k_B T \ln 2 \) worth of energy as heat. To see this we can simply remove the membrane (a reversible process) and then push in, slowly, a fresh partition from the right, as depicted in Fig. 1.2. When the partition reached halfway the ‘memory’ has been reset to the bit value 0 and, of course, all trace of the original bit value has been lost. The work that needs to be done to achieve this is $$ W = - \int_{0}^{V/2} \frac{P}{V} dV = k_B T \ln 2, $$ and this is dissipated, of course, as heat. We can view this as a resolution of the paradox implicit in Szilard’s model. This is not the end of the story, however. It has recently been shown that Landauer’s limit can be beaten if we pay a cost, not in energy, but in some other quantity such as angular momentum (Vacarro and Barnett 2011). The key idea to take from these models, however, is unaffected: information is physical. ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 14 Context: ```markdown # 2 Quantum Communications and Quantum Key Distribution Quantum communications differ from their classical counterpart in that the transmitted signal is carried by a quantum system. At its simplest, classical information is expressed in bits and is carried by a physical system with two distinct states (for example, a high or low voltage or the presence or absence of an optical pulse). One state is used to represent the logical 0 and the other a logical 1. We can take the same approach in quantum communications and use two orthogonal quantum states to represent 0 and 1. We label these, naturally enough, as |0⟩ and |1⟩. The additional element brought in by using a two-state quantum system is that we can also prepare any superposition state of the form $$ |\psi\rangle = \alpha |0\rangle + \beta |1\rangle, \tag{2.1} $$ where α and β are complex probability amplitudes. A quantum bit, or qubit, is such a two-state quantum system. ## 2.1 Qubits Before getting into the theory of quantum communications, we pause to elaborate on the idea of a qubit and the mathematical tools used to describe it. A qubit can be any quantum system with two orthogonal states. We choose a basis, often called the computational basis in quantum information, and label the two states in this basis as |0⟩ and |1⟩. It is convenient to think of this as a spin-half particle; this is not literally true in most cases, but it has the benefit that we can use the Pauli operators to describe the properties of the qubit. There are four Pauli operators, which are \( \sigma_x \), \( \sigma_y \), and \( \sigma_z \) and the identity operator \( I \). We can define each of these by their action on the states in the computational basis: $$ \sigma_x |0\rangle = |1\rangle \quad \sigma_x |1\rangle = |0\rangle $$ $$ \sigma_y |0\rangle = i|1\rangle \quad \sigma_y |1\rangle = -i|0\rangle $$ $$ \sigma_z |0\rangle = |0\rangle \quad \sigma_z |1\rangle = -|1\rangle $$ $$ I |0\rangle = |0\rangle \quad I |1\rangle = |1\rangle \tag{2.2} $$ The first three Pauli operators do not mutually commute. We can write the product rule for these operators in an appealingly simple form if we introduce, by means of a ... ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 16 Context: ```markdown # Information Security Figure 2.1: Elements of a secret communications channel. Reproduced, with permission, from Bartlett (2009). Example: The most common symbol will be E, which occurs 12.7% of the time, while Q makes up only about 0.1% of the symbols (or perhaps a bit more in these notes). Sherlock Holmes makes use of precisely this technique in one of his cases (Conan Doyle 1903). It was Shannon who gave us an objective criterion for perfect secrecy (Shannon 1949). Let \( \{p_i\} \) be the set of possible plaintexts (messages) and \( \{c_j\} \) be the set of possible ciphertexts. Shannon's criterion for perfect secrecy is: \[ P(c_j | p_i) = P(c_j) \quad \forall i, j. \] A straightforward application of Bayes' theorem shows that this is equivalent to: \[ P(p_i | c_j) = P(p_i) \quad \forall i, j. \] This means that discovering or intercepting the ciphertext does not provide any information on the plaintext. The second condition states that any given ciphertext is equally likely to have been generated by any plaintext. A question that you might like to ponder is how many possible keys does this require? The simplest perfectly secure cipher is the Vernam cipher, or one-time pad. It uses a key in the form of a random sequence of bits, \( \cdots 111100 \cdots \), that is at least as long as the plaintext (which is also a sequence of bits, of course). The ciphertext is produced by bit-wise modulo addition of the plaintext and the key: \[ \begin{align*} 0 \oplus 0 &= 0 \\ 0 \oplus 1 &= 1 \\ 1 \oplus 0 &= 1 \\ 1 \oplus 1 &= 0. \end{align*} \] A simple example is: \[ \begin{align*} P & \cdots 00110100 \cdots \\ K & \cdots 11101100 \cdots \end{align*} ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 19 Context: ```markdown ## 2.4 Optical polarization Recall that for a plane wave, the electric field \(\mathbf{E}\), the magnetic field \(\mathbf{H}\), and the wavevector \(\mathbf{k}\) are all mutually orthogonal and are oriented such that \(\mathbf{E} \times \mathbf{H}\) points in the direction of \(\mathbf{k}\) (see Fig. 2.2). This fixes \(\mathbf{E}\) and \(\mathbf{H}\) to be in the plane perpendicular to \(\mathbf{k}\). ![Fig. 2.2](attachment.png) *Relative orientations of the electric and magnetic fields and the wavevector. Reproduced, with permission, from Barnett (2009).* Consider a complex electric field for a plane wave propagating in the \(z\)-direction: \[ \mathbf{E} = \mathbf{E}_0 e^{i(\mathbf{k} \cdot \mathbf{r} - \omega t)}. \tag{2.13} \] We can characterize the polarization by the direction of the complex vector \(\mathbf{E}_0\) in the \(x - y\) plane: \[ \mathbf{E}_0 = E_{0x} \hat{\imath} + E_{0y} \hat{\jmath}. \tag{2.14} \] or as a column vector, the Jones vector: \[ \mathbf{E}_0 = \begin{bmatrix} E_{0x} \\ E_{0y} \end{bmatrix}. \tag{2.15} \] Only the relative sizes of \(E_{0x}\) and \(E_{0y}\) matter, so we can use a normalized Jones vector. The Jones vectors corresponding to horizontal/vertical, diagonal, and circular polarizations are depicted in Fig. 2.3. For a single photon, we can associate each of the Jones vectors with a qubit state according to the mapping: \[ \begin{bmatrix} \alpha \\ \beta \end{bmatrix} \rightarrow \alpha |0\rangle + \beta |1\rangle, \tag{2.16} \] which leads to the identifications listed in Fig. 2.4. This simple idea has been used widely in experimental demonstrations of a variety of quantum information and communications protocols, most especially in quantum cryptography. ## 2.5 Quantum cryptography Quantum cryptography, or perhaps more precisely quantum key distribution, has become an advanced experimental technique and is on the verge, perhaps, of becoming a... ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 22 Context: ```markdown # Quantum Cryptography Quantum money is impractical but Bennett and Brassard (1984) proposed a variant on this idea: quantum key distribution. The idea is that Alice associates the bit values 0 and 1 with a linear polarization state (either horizontal/vertical or diagonal/anti-diagonal): $$ H \; \text{or} \; D \; \longleftarrow \; 0 \\ V \; \text{or} \; A \; \longleftarrow \; 1. $$ Suppose that Alice prepares a vertically polarized photon and that Bob measures the state in the horizontal/vertical basis. An eavesdropper, Eve, does not know that the photon was prepared in this basis and so can only make a choice of what to measure. In this way she will introduce, for $\frac{1}{4}$ of the photons intercepted, a disagreement between the values observed by Alice and Bob. This 25% error rate indicates to Alice and Bob the activity of the eavesdropper. All that is needed is a sequence of instructions (a protocol) to ensure that Eve is trapped in this way. One such protocol is depicted in Fig. 2.6. Alice prepares a random sequence of bits and randomly encodes each onto the polarization as either a horizontally/vertically or diagonally/anti-diagonally polarized photon, which she sends to Bob. For each photon, Bob randomly (and independently of Alice, of course) chooses to make a polarization measurement in one of the two bases. Roughly half the time he will guess correctly and half incorrectly. Bob then uses a classical channel to tell Alice which basis he used in each time slot for which he detected a photon (but not, of course, the measured value). Alice tells Bob the slots in which he made the correct choice (time-slots 2, 4, 6, 8, 9, 11, 14, 15, 16, and 19, in the case depicted in Fig. 2.6). These should comprise a secret shared random bit string (0111011010 in this case) which can be used as a secret key. | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | |---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|----|----|----|----| | → | → | → | → | → | → | → | → | → | → | → | → | → | → | → | → | → | → | → | | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | | X | X | X | X | X | X | X | X | X | X | X | X | X | X | X | X | X | X | X | | | ± | X | ✗ | ± | X | ✓ | ✗ | ± | ✗ | ± | ✗ | ± | X | ✓ | ± | ✗ | ± | X | | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | **Fig. 2.6** An example of a quantum cryptographic protocol. Alice prepares single photons in one of two polarization bases and these are measured by Bob. Reproduced, with permission, from Barrett (2009). ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 25 Context: ```markdown # 2.2 Generalized Measurements If we perform a measurement of \( A \) and find the value \( \lambda_b \), then we know that the post-measurement state is \( | \lambda_b \rangle \), and repeating the measurement, if done quickly enough, should give the same result. There is one further point that we need to consider, which is that the eigenvalues of \( A \) might be degenerate, which means that a set of orthonormal eigenvectors, \( | \lambda_j \rangle \), will correspond to the same measurement outcome, \( \lambda_b \). To incorporate this case, it is useful to introduce a projector onto the set of states with a common eigenvalue: \[ \hat{P}_b = \sum_j | \lambda_j \rangle \langle \lambda_j |. \tag{3.5} \] The probability that the measurement will give the result \( \lambda_b \) is then \[ P(\lambda_b) = \sum_j \langle \lambda_j | \hat{P}_b | \lambda_j \rangle = \text{Tr}(\hat{P}_b \hat{\rho}). \tag{3.6} \] The post-measurement state will simply be that part of the pre-measurement state that lies in the subspace spanned by the corresponding eigenstates or, in other words, that part of the state selected by the projector. Hence if our measurement gives the result \( \lambda_b \), then the density matrix changes as follows: \[ \hat{\rho} \rightarrow \frac{\hat{P}_b \hat{\rho} \hat{P}_b}{\text{Tr}(\hat{P}_b \hat{\rho})}, \tag{3.7} \] where the denominator, which is the prior probability for the observed measurement result, ensures correct normalization of the post-measurement state. Let us conclude this brief review of von Neumann measurements with a summary of the properties of projectors. ## Properties of Projectors 1. They are Hermitian, \( \hat{P}_b = \hat{P}_b^\dagger \). 2. They are positive operators, \( \hat{P}_b \geq 0 \). 3. They are complete, \( \sum_b \hat{P}_b = \hat{I} \). 4. They are orthonormal, \( \hat{P}_b \hat{P}_{b'} = \hat{P}_b \delta_{bb'} \). Here \( \hat{I} \) is the identity operator. We note that the first three of these properties have physical significance in that they are required in order that the probability rule, \( P(\lambda_b) = \text{Tr}(\hat{P}_b \hat{\rho}) \), be true. They correspond, respectively, to the requirements that the projectors are observables, that they give positive probabilities, and that the probabilities for the complete set of possible outcomes must sum to unity. The final property, however, does not seem to have a similar physical significance and, indeed, we shall see that generalized measurements correspond to dropping this requirement. ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 26 Context: ```markdown ## 3.2 Non-ideal measurements Most measurements are not of the form described in the preceding section. Consider, for example, the operation of a photodetector. Real photodetectors have a finite efficiency and so do not resolve perfectly the number of photons. In detecting the photons, moreover, the detector absorbs the light and so leaves the field in its zerophoton (or vacuum) state. Hence neither the von Neumann forms for the detection probabilities nor for the post-measurement state are appropriate and something more general is required. As a simple example, both of the problem and of how we might proceed, let us consider a measurement of a spin-component for a single qubit. The ideal measurement would correspond to the pair of projectors \[ \hat{P}_0 = |0\rangle\langle 0| \quad \hat{P}_1 = |1\rangle\langle 1| \tag{3.8} \] Suppose that our detector gives the wrong answer with probability \( p \) so that the two possible measurement results occur with probabilities \[ P(0) = (1 - p) \text{Tr}(\hat{\rho} \hat{P}_0) + p \text{Tr}(\hat{\rho} \hat{P}_1) \tag{3.9} \] \[ P(1) = (1 - p) \text{Tr}(\hat{\rho} \hat{P}_1) + p \text{Tr}(\hat{\rho} \hat{P}_0) \tag{3.10} \] the sum of which is clearly unity, as it should be. We can write these in a form reminiscent of the von Neumann expressions: \[ P(0) = \text{Tr}(\hat{\rho} \hat{P}_0) \] \[ P(1) = \text{Tr}(\hat{\rho} \hat{P}_1) \tag{3.11} \] by introducing the probability operators \[ \hat{\Pi}_0 = (1 - p) \hat{P}_0 + p \hat{P}_1 \] \[ \hat{\Pi}_1 = (1 - p) \hat{P}_1 + p \hat{P}_0 \tag{3.12} \] These operators satisfy the first three properties that we listed for the projectors; they are Hermitian, positive and complete. They are not orthonormal, however: \[ \hat{\Pi}_0 \hat{\Pi}_1 = p(1 - p) \hat{1}. \] This is our first indication of a more general description of the measurement process, which we develop further below. ## 3.3 Probability operator measures To calculate the portability for any given result of a generalized measurement we need a probability rule and, in particular, a set of operators that characterize the measurement, one for each of the possible measurement outcomes. The required operators are ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 27 Context: ```markdown # Generalized Measurements The probability operators, the set of which is a probability operator measure or a positive operator-valued measure (Helstrom 1976, Holevo 1982, 2001, Peirs 1993, Barnett 2009). That the first three of the properties we listed for the projectors have physical significance, but the third does not, tells us in what way we are allowed to generalize the von Neumann description; we simply drop the fourth and final property from our list. Hence we describe any measurement by a set of probability operators \(\{\hat{P}_m\}\) such that the probability for getting measurement outcome \(m\) is \[ P_m = \text{Tr}(\hat{\rho} \hat{P}_m), \tag{3.13} \] where the probability operators have the following three properties: ## Properties of Probability Operators 1. They are Hermitian, \(\hat{P}_m = \hat{P}_m^\dagger\). 2. They are positive operators, \(\hat{P}_m \geq 0\). 3. They are complete, \(\sum_m \hat{P}_m = \hat{1}\). We should emphasise that there is no restriction on the number of probability operators; the number can be greater or less than the dimension of the state space. For example, we shall analyze an example in which a generalized measurement on a qubit (which has three outcomes, even though the dimension of the state space is only 2). There is no need, moreover, for the probability operators to commute with each other. The set of probability operators characterizing a measurement is called a probability operator measure (POM) which you will also find called a positive operator-valued measure (POVM). The latter has become the commonly used expression, but I prefer the former*. The description of a measurement in terms of a POM is very useful because of two points: 1. All measurements can be described in this way. (This is at least reasonable given the physical significance of the three properties used to define a POM.) 2. Any set of the probability operators (that is any POM) is realizable, at least in principle, in the laboratory. This combination is very useful because if we seek to find the best possible measurement in our situation, we can separate out the purely mathematical consideration of the POM from the experimental question of how to achieve it. That any POM is realizable as a measurement is a consequence of Naimark's theorem. We shall not prove this here but rather give an indication of how it works. A more complete presentation may be found in (Barnett 2009). The key idea is to map the generalized measurement onto a projective, or von Neumann, measurement in an extended state space. To see *POM or POVM? The term "probability operator measure" tells us that the elements forming the measure are the probability operators. The more popular expression, positive operator-valued measure, expresses the fact that the elements of the measure, the probability operators, are positive operators. Calling the set of operators a POM reminds us of their physical significance, while the term POVM recalls their mathematical properties. ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 29 Context: ```markdown # 26 Generalized Measurements Comparing this with our normalisation condition leads us to identify our probability operators as $$ \hat{\rho}(x_m,p_m) = \frac{1}{2\pi \hbar} \int \mathrm{d}x_m \, \hat{p}_m \, \hat{\rho}(x_m,p_m) \, \hat{p}_m. $$ It follows, for example, that the probability distribution for the measured position is $$ P(x_m) = \int_{-\infty}^{\infty} \mathrm{d}x \, | \psi(x) |^2 \exp \left[ - \frac{(x - x_m)^2}{2\sigma^2} \right]. $$ which is a convolution of the true momentum distribution, $\langle \psi | \hat{p} | \psi \rangle$, with a Gaussian of width associated with the state $\hat{\rho}(x_m, p_m)$. A similar expression applies also for the measured momentum distribution. The variances found for the measurement results are: $$ \begin{align*} \text{Var}(x_m) &= \Delta x^2 + \sigma^2, \\ \text{Var}(p_m) &= \Delta p^2 + \frac{\hbar^2}{4\Delta^2}. \end{align*} $$ The additional contributions, over and above $\Delta x^2$ and $\Delta p^2$, are a consequence of the fact that we have performed a simultaneous measurement of two incompatible observables. ## 3.4 Optimized measurements We can seek the best possible measurement in any given situation in two stages: first we have the mathematical optimization by finding the best POM and secondly design an experiment that gives the corresponding probabilities. The mathematical optimization is simply a search over all possible sets of probability operators forming a POM. The optimal measurements to perform have been determined in a number of cases and some of these have been realised in the laboratory (Cheffies 2000, Paris and Réháček 2004, Bergou 2007, Barnett 2009, Barnett and Croke 2009). Let us begin by considering a simple example motivated by our treatment of quantum communications. Suppose we have a qubit which we know to have been prepared in one of two non-orthogonal states $|h_1\rangle$ or $|h_2\rangle$: $$ \langle h_1 | h_2 \rangle \neq 0. $$ We can use our probability operators to ask whether a measurement exists that will determine which state has been prepared with certainty. Not surprisingly, the answer is no, but we can prove this. To proceed, we seek two probability operators, $\hat{\rho}_1$ and $\hat{\rho}_2$, such that $$ \langle h_1 | \hat{\rho}_1 | h_1 \rangle = 1 = \langle h_2 | \hat{\rho}_1 | h_2 \rangle, $$ $$ \langle h_1 | \hat{\rho}_2 | h_2 \rangle = 0 = \langle h_2 | \hat{\rho}_2 | h_1 \rangle. $$ ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 30 Context: ```markdown # Optimized measurements \[ \hat{\pi}_1 + \hat{\pi}_2 = \mathbb{I}. \] From our first condition, \(\langle \psi_1 | \hat{\pi}_1 | \psi_1 \rangle = 1\), we can write \[ \hat{\pi}_1 = |\psi_1\rangle\langle \psi_1| + \hat{A}, \] where \(\hat{A}\) is a Hermitian, positive operator such that \(\langle \psi_1 | \hat{A} | \psi_1 \rangle = 0\), which implies that \(\hat{A}|\psi_1\rangle = 0\). From this it follows that \[ \langle \psi_2 | \hat{\pi}_2 | \psi_2 \rangle = \langle \psi_2 | |\psi_1\rangle|^2 + \langle \psi_2 | \hat{A} | \psi_2 \rangle \] which, being the sum of a positive quantity and a quantity greater than or equal to zero, must be greater than zero. Hence we cannot discriminate between these states perfectly. A natural question then is "what is the best we can do?". The answer depends, of course, on what we mean by "best". Here we consider only two such strategies: measurement with the minimum probability of error and unambiguous state discrimination. ## 3.4.1 Maximum probability of being correct Consider the following task, motivated by our discussion of quantum communications. We are given a quantum system which we know to have been prepared in one of a set of possible states \(\{|\psi_j\rangle\}\) and also the probabilities \(\{p_j\}\) that each state was prepared. We seek to identify the state with the maximum probability of being correct or, equivalently, with the minimum value of the error probability. Hence we construct a POM with probability operators \(\{\hat{\pi}_k\}\) and associate each measurement outcome, \(k\), with the corresponding state \(\rho_k\) and then minimize the quantity \[ P_{\text{error}} = 1 - \sum_j p_j \langle \psi_j | \hat{\pi}_k | \psi_j \rangle. \] Remarkably, the necessary and sufficient conditions for reaching this minimum are known (Holevo 1973, Helstrom 1976, Barnett 2009): \[ \hat{\pi}_k (p_j \rho_j - p_k \rho_k) \hat{\pi}_k = 0 \] \[ \sum_j p_j \hat{\pi}_k - p_k \hat{\pi}_k \geq 0. \] A simple derivation of these conditions is given in (Barnett and Croke 2009a). These conditions do not provide a direct means to construct the minimum error measurement and, indeed, there are many cases in which the strategy for measuring with minimum probability of error is not unique. Our strategy, therefore, is to try a measurement strategy and if it satisfies these conditions then we know it is optimal. The problem is usually a tractable one where there is some geometry amongst the set of possible states and the minimum-error strategy has been derived in a variety of cases (Chefles 2000, Paris and Réfréjac 2004, Bergou 2007, Barnett 2009, Barnett and Croke 2009b). If we have just two possible states, \(|\psi_1\rangle\) and \(|\psi_2\rangle\), then the minimum-error measurement is known: we need only perform a projective (or von Neumann) measurement in which ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 31 Context: ```markdown # 2.8 Generalized Measurements The two measurement outcomes correspond to projectors onto the positive and negative eigenvalues of ρ̃1 and ρ̃2, corresponding, respectively, to identifying the state as ρ̃1 and ρ̃2. This gives us the minimum error probability the Helstrom bound: \[ p_{\text{min error}} = \frac{1}{2} \left( 1 - \text{Tr} \left[ \rho \hat{\pi}_1 - \rho \hat{\pi}_2 \right] \right). \tag{3.30} \] It is interesting to note that sometimes a measurement does not help and the minimum-error strategy is simply to guess that the most likely state was prepared (Hunter 2003). As an example, let us suppose that we have a single qubit which we know to have been prepared with equal probability ($p_1 = \frac{1}{2} = p_2$) in one of the two non-orthogonal states: \[ |\varphi_1\rangle = \cos(\theta/2)|0\rangle + \sin(\theta/2)|1\rangle, \tag{3.31} \] \[ |\varphi_2\rangle = \cos(\theta/2)|0\rangle - \sin(\theta/2)|1\rangle, \tag{3.32} \] so that the overlap of the states is \[ \langle \varphi_1 | \varphi_2 \rangle = \cos 2\theta. \tag{3.33} \] It is straightforward to confirm that the minimum error strategy corresponds to the two probability operators \[ \hat{\pi}_1 = \frac{1}{2} \left( |0\rangle \langle 0| + |1\rangle \langle 1 | \right) = |\varphi_1\rangle\langle\varphi_1|, \tag{3.34} \] \[ \hat{\pi}_2 = \frac{1}{2} \left( |0\rangle \langle 0| - |1\rangle \langle 1| \right) = |\varphi_2\rangle\langle\varphi_2|. \tag{3.35} \] The arrangement of these states is depicted in Fig. 3.1. We see that the optimal measurement in this case corresponds to projection onto one of a pair of states $\{ |\varphi_1\rangle \text{ or } |\varphi_2\rangle \}$. The error probability arises from the fact that $|\varphi_1\rangle$ is not perpendicular to $|\varphi_2\rangle$. A simple experiment has been performed at this limit to discriminate between two states of photon linear polarization (Barnett and Ruis 1997). By no means all optimal measurements are von Neumann measurements. Indeed, a generalized measurement is normally required. As a simple illustration, consider the trine ensemble in which a qubit is prepared (with equal probability) in one of three states: \[ |\varphi_1\rangle = |0\rangle, \tag{3.36} \] \[ |\varphi_2\rangle = \frac{1}{\sqrt{2}} \left( |0\rangle + \sqrt{3}|1\rangle \right), \tag{3.37} \] \[ |\varphi_3\rangle = \frac{1}{2} \left( |0\rangle + \sqrt{3}|1\rangle \right). \tag{3.38} \] These correspond to states separated by 120° on a great circle of the Bloch sphere. As depicted in Fig. 3.2, the minimum-error strategy in this case corresponds to the three probability operators \[ \hat{\pi}_1 = \frac{2}{3}|\varphi_1\rangle\langle\varphi_1| \tag{3.39} \] and gives an error probability of \(\frac{1}{3}\), so that this measurement strategy determines the correct state with probability \(\frac{2}{3}\). The required generalized measurement has been ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 35 Context: ```markdown # 3.2 Generalized Measurements \[ \hat{\rho} \rightarrow \frac{\hat{P}_i \hat{\rho} \hat{P}_i^\dagger}{\text{Tr}(\hat{P}_i \hat{\rho})}. \tag{3.42} \] It should be noted that a set of Kraus operators \(\{ \hat{A}_i \}\) determine uniquely a corresponding set of probability operators \(\{ p_i \}\), but the converse is not true; assigning the probability operators does not determine a unique transformation on the state. ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 36 Context: ```markdown # 4 Entanglement and its Applications More than any other feature, it is entanglement that gives quantum theory its distinctive character. It is the source of paradoxes, the most famous of which is the much discussed EPR paradox (Einstein et al. 1935, Bohr 1935, Wheeler and Zurek 1983, Whitaker 2006), or tests of distinctive ‘quantumness’, such as the violation of Bell’s famous inequality (Bell 1964, 1987), and it underlies some of the more unexpected (and headline-grabbing) features of quantum information such as teleportation (Bennett et al. 1993). ## 4.1 Entangled States and Non-locality We should start by stating what entanglement is. The simplest answer is that it is the distinctive property of entangled states, which leads us to ask “what are entangled states?”. This is, in fact, a surprisingly difficult question to answer, at least in full generality. For the purposes of these all too brief lectures we shall avoid completely the tricky issue of entanglement for mixed states and discuss only pure states. For pure states there is a clear definition but it is the definition of states that are *not* entangled. A state that is not entangled is a state of two or more quantum systems that can be factorized into a product of single-system states. States that do not have this property are entangled. For two quantum systems, A and B, the combined state, |\psi\rangle_{AB}, is entangled if \[ |\psi\rangle_{AB} \neq |\psi\rangle_A \otimes |\psi\rangle_B. \tag{4.1} \] Consider, for example, the two-qubit state \[ |\psi\rangle = \cos(\theta)| 0 \rangle | 1 \rangle - \sin(\theta)| 1 \rangle | 0 \rangle. \tag{4.2} \] This state will not be entangled if \(\theta = \pi/2\), but will be entangled for all other values of \(\theta\). For entangled states, the properties of the A and B systems are quantum correlated. We can see this in the above example in that determining whether the first qubit is in the state \(|0\rangle\) or the state \(|1\rangle\) also determines the, previously undetermined, state of the second qubit. The implications of the existence of entanglement are profound and many. In these lectures we shall address only five: 1. EPR and related non-locality paradoxes. ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 37 Context: ```markdown ## 34 Entanglement and its Applications 1. The ability to perform “magic”. 2. Quantum dense coding. 3. Teleportation. 4. Dramatic speed up in quantum computing. We shall treat the first four of these in this lecture and leave the final one for the next and final lecture. Let us begin with the EPR, in the form given by Bohm (1951). To this end, consider two qubits in the entangled state \[ |\psi\rangle_{AB} = \frac{1}{\sqrt{2}} \left( |00\rangle_{A} |1\rangle_{B} - |1\rangle_{A} |0\rangle_{B} \right) . \] Let us suppose that qubit A is held by Alice and qubit B by Bob and that they are at a considerable distance from each other. If either party measures their qubit in any basis then they find either of two possible results, each occurring with probability \( \frac{1}{2} \). If they measure the same observable as each other then they find opposite or anti-correlated results. This is a simple consequence of the eigenvalue equation: \[ a \cdot \hat{A} \cdot |\psi\rangle = -|\psi\rangle , \] which holds for all unit vectors a. The paradox is that a measurement by Alice of her particle will instantaneously project the state of its partner into an eigenstate of the observable selected by Alice. If we assume that Alice has a free choice of what to measure and that any influence of her measurement cannot travel arbitrarily fast, then Bob's qubit must have carried values for all possible observables, something that is clearly at odds with complementarity. We give, here, only a partial resolution of this in the form of the no-signalling theorem. ### 4.1.1 Bell's theorem Correlations are also common in the classical world and, indeed, under classical communications. Are not the quantum correlations associated with entanglement simply the same thing? It was Bell's theorem, in the form of the violation of his celebrated inequality, that gave the definitive answer "no". We present here a derivation of Bell's inequality, in its most common form (Clauser et al. 1969, Bell 1987). Let us start by thinking of our qubit as a spin-half particle. A measurement of the spin along a direction in space, given by the unit vector a, will reveal the spin to be aligned or anti-aligned with this direction. We write the first of these as +1 and the second as -1, so that in any given measurement our measurement result A with bet 1. We can do the same thing for the second qubit (entangled with the first) and write the measurement result as B = ±1. If we take the product of these two values and average over many experimental realizations then we obtain the correlation function \[ E(a, b) = \langle AB \rangle , \] which is clearly bounded in magnitude: ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 41 Context: ```markdown # 3.8 Entanglement and its Applications **[Hardy’s]** \[ |Hardy\rangle = \frac{\sqrt{2}}{3}|0\rangle_A \otimes |0\rangle_B + \frac{1}{\sqrt{3}}|0\rangle_A \otimes |1\rangle_B = \frac{1}{\sqrt{3}}|1\rangle_A \otimes |0\rangle_B + \frac{\sqrt{2}}{3}|0\rangle_A \otimes |0\rangle_B, \] where \(|0\rangle^{\prime} = 2^{-1/2}(|0\rangle + |1\rangle)\) is the eigenstate of \(\hat{d}_s\) with eigenvalue +1. The following statements follow directly from the form of \([Hardy]\): 1. If both Alice and Bob measure the observable corresponding to \(\hat{d}_s\), with eigenstates \(|0\rangle\) and \(|1\rangle\), then at least one of them will get the result +1, corresponding to the state \(|0\rangle\). 2. If Alice measures \(\hat{d}_s\) and gets the value +1 then a measurement by Bob of \(\hat{d}_v\) will, with certainty, find the value +1, corresponding to the state \(|0\rangle\). 3. If Bob measures \(\hat{d}_v\) and gets the value +1 then a measurement by Alice of \(\hat{d}_s\) will, with certainty, find the value +1, corresponding to the state \(|0\rangle\). Local realistic ideas lead us to treat as simultaneously real the values ±1 of the observables corresponding to the operators \(\hat{d}_s\) and \(\hat{d}_v\). The values of these, which we denote \(a\) and \(v\), respectively, should be independent of any choice of an observation carried out on the other qubit. This leads us to express the above three properties as the following probabilities: \[ P(a^A = -1, b^B = -1) = 0 \] \[ P(a^A = +1|b^B = +1) = 1 \] \[ P(a^A = +1|b^B = +1) = 1. \] The first of these tells us that at least one of the properties \(a^A\) and \(b^B\) must take the value +1 and the following two then tell us that at least one of the properties \(a^A\) and \(b^B\) must take the value +1. It is a principle of local realism, therefore, that \(a^A\) and \(b^B\) cannot both take the value -1: \[ P(a^A = -1, b^B = -1) = 0. \] A quantum mechanical treatment, however, shows that measurement by both Alice and Bob of \(\hat{d}_s\) can both give the result +1 and that this occurs with probability \(\frac{1}{2}\). This is clearly at odds with the local-realistic reasoning presented above. ## 4.3 Ebits and Shared Entanglement In quantum information, the notion of entanglement not as a mystery, but rather as a resource to be exploited. The first question to be addressed, as with any resource, is to decide how to quantify it. This is a subtle question but we can give, at least, a simple preliminary answer in terms of “ebits”. If two spatially separated individuals share a ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 58 Context: ```markdown # 5.5 Errors and decoherence So what stops us building a quantum processor, revolutionising computation and breaking into RSA? The short answer is that we don’t yet have any suitably scalable implementation of quantum logic elements such as qubits and gates. Many technical challenges remain to be solved before we can build a quantum computer to challenge current devices based on classical logic. I mention here only one problem, that of decoherence. In a quantum computer our information is encoded onto two-state quantum systems, our qubits and these are made to interact with each other by the implementation of desired Hamiltonians. Yet the quantum nature, both of the qubits and of the Hamiltonian, makes them extremely sensitive to their environment and even weak interactions can have a disastrous effect. As an illustration, let us consider the effect of a single-qubit error in an implementation of Deutsch’s algorithm. To keep things simple, let us consider only a phase error: $$|0\rangle \rightarrow |0\rangle \quad |1\rangle \rightarrow |1\rangle \quad (5.28)$$ and a bit-flip error: $$|0\rangle \rightarrow |1\rangle \quad |1\rangle \rightarrow |0\rangle \quad (5.29)$$ Recall that we obtain the desired information, as to whether the computed function is constant or balanced, by measuring the first qubit to be in the state $2^{-1/2}(|0\rangle + |1\rangle)$ or $2^{-1/2}(|0\rangle - |1\rangle)$, respectively. If a bit-flip error occurs for this qubit then we are safe, but if a phase-error occurs then we get the wrong answer! Clearly we need to work hard to suppress all sources of errors and decoherence, but this is not the end of the problem. For large-scale computations we need a large number of qubits and the scaling is not at all favorable. To see this let us suppose that the probability that a single qubit has no error in a time $t$ is: $$\exp(-\Gamma t).$$ If we have \( n \) qubits then the probability that none of these experiences an error in this time is $$\exp(-n\Gamma t),$$ which is exponential in \( n \). But worse is to come. Let us suppose that \( t \) is the typical amount of time it takes to perform a single gate operation. If we need a sequence of \( m \) of these then we find $$\exp(-m\log n t).$$ Typically we might need each qubit to interact with every other qubit so \( m \) may be of the same order as \( n \). We do not need to perform the gate operations one at a time, of course, and by suitably optimising the order of operations, we might have \( m \approx n \log n \) to give a final zero-error probability of $$\exp(-n\log n t). \quad (5.30)$$ For 300 qubits, the exponent is about 2,000 times smaller than the single-qubit and single-gate error rate, $e^{-T}$. The zero-error probability is the \( 2,000^{th} \) power of the no error probability for a single qubit and a single-gate operation. ``` #################### File: Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf Page: 63 Context: ```markdown # References Leff, H. S. and Rex, A. F. (eds.) (1990) Maxwell's demon: entropy, information, computing. Adam Hilger, Bristol. Leff, H. S. and Rex, A. F. (1994) Entropy of measurement and erasure: Szilard's memoir revisited. *Am. J. Phys.* 52, 3495-3499. Reprinted in (Leff and Rex 2003). Leff, H. S. and Rex, A. F. (2003) Maxwell's demon 2: entropy, classical and quantum information, computing. Institute of Physics Publishing, Bristol. Loepz, S. and Wootters, W. K. (2006) Protecting information: from classical error correction to quantum cryptography. (Cambridge University Press, Cambridge). Mattke, K., Weinfurter, H., Kwiat, P. G. and Zeilinger, A. (1996) Dense coding in experimental quantum communication. *Phys. Rev. Lett.* 76, 4656–4659. Maxwell, J. C. (1871) Theory of heat. Longmans, Green, and Co., London. Mcayre, S. B. (2011) The theory that would not die. Yale University Press, New Haven. Mermin, D. (1990) What's wrong with these elements of reality? *Physics Today* June issue 9–11. Mermin, D. (2007) Quantum computer science. Cambridge University Press, Cambridge. Moore, G. E. (1965) Cramming More Components onto Integrated Circuits. *Proc. IEEE* 86, 82–85. Nielsen, M. A. and Chuang, I. L. (2000) Quantum computation and quantum information. Cambridge University Press, Cambridge. Pachos, J. K. (2012) Introduction to topological quantum computation. Cambridge University Press, Cambridge. Peres, A. (1989) How to differentiate between two non-orthogonal states. *Phys. Lett.* A 128, 19–19. Peres, A. (1993) Quantum theory: concepts and methods. Academic, Dordrecht. Pleno, M. and Vitalli, V. (2001) The physics of forgetting: Landauer's erasure principle and information theory. *Contemp. Phys.* 42, 25–60. Phoenix, S. J. D. and Townsend, P. D. (1995) Quantum cryptography: how to beat the code breakers using quantum mechanics. *Contemp. Phys.* 36, 165–195. Piper, F. and Murphy, S. (2002) Cryptography: a very short introduction. Oxford University Press, Oxford. Raussendorf, R., Browne, D. E. and Briegel, H. J. (2003) Measurement-based quantum computation on cluster states. *Phys. Rev. A* 68, 022312. Redhead, M. (1987) Incompleteness, Nonlocality and Realism. Clarendon Press, Oxford. Scarani, V., Illidis, S., Gisin, N. and Acín, A. (2005) Quantum cloning. *Rev. Mod. Phys.* 77, 1225–1256. Scaroni, V., Bechmann-Pasquinucci, H., Cerf, N. J., Dušek, M., Litkehuens, N. and Pev, M. (2009) The security of practical quantum key distribution. *Rev. Mod. Phys.* 81, 1301–1350. Shannon, C. E. (1948) A mathematical theory of communication. *Bell Sys. Tech. J.* 27, 379–423 and 623–656. ``` ########## """QUERY: Please summarize the whole context. It is important that you include a summary for each file. All files should be included, so please make sure to go through the entire context""" Consider the chat history for relevant information. Use all information included. Use as much tokens as needed. Important: If you find information separated by a | in the context, it is a table formatted in Markdown. Final Files Sources: Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 1, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 2, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 6, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 7, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 9, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 10, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 11, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 13, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 14, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 16, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 17, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 19, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 20, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 21, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 23, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 24, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 25, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 26, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 27, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 29, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 30, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 31, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 32, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 34, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 36, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 37, Web%20API%20Design%20-%20Brian%20Mulloy%20%28PDF%29.pdf - Page 38, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 1, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 3, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 4, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 5, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 6, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 7, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 8, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 9, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 10, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 12, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 13, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 15, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 17, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 19, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 20, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 22, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 23, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 26, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 28, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 29, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 30, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 31, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 32, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 33, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 34, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 35, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 37, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 38, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 39, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 43, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 45, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 46, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 47, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 48, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 49, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 50, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 51, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 52, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 53, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 54, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 55, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 57, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 58, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 60, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 62, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 63, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 65, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 66, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 69, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 70, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 73, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 81, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 84, Project%20Oberon%20The%20Design%20of%20an%20Operating%20System%2C%20a%20Compiler%2C%20and%20a%20Computer%20-%20Niklaus%20Wirth%2C%20J%C3%BCrg%20Gutknecht%20%28PDF%29%20PO.Applications.pdf - Page 86, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 2, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 10, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 18, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 21, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 24, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 30, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 32, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 35, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 36, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 38, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 41, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 43, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 52, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 64, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 69, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 70, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 73, The%20Little%20Book%20About%20OS%20Development%20-%20Erik%20Helin%2C%20Adam%20Renberg%20-%20%28PDF%2C%20HTML%29.pdf - Page 74, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 3, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 5, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 6, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 8, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 10, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 14, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 16, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 19, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 22, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 25, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 26, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 27, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 29, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 30, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 31, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 35, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 36, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 37, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 41, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 58, Introduction%20to%20Quantum%20Information%20-%20Stephen%20M.%20Barnett%20%28PDF%29.pdf - Page 63 ================================================== **Elapsed Time: 189.37 seconds** ================================================== FINAL ANSWER Answer: ================================================== **Elapsed Time: 0.00 seconds** ==================================================